mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
Merge branch 'master' into add-path
Conflicts: filter/filter.c nest/proto.c nest/rt-table.c proto/bgp/bgp.h proto/bgp/config.Y
This commit is contained in:
@@ -193,7 +193,14 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
|
||||
else if (tk->code == 'C') {
|
||||
c1 = 1;
|
||||
struct f_val *val = tk->a1.p;
|
||||
if (val->type == T_IP) {
|
||||
|
||||
if (val->type == T_INT) {
|
||||
ipv4_used = 0; key = val->val.i;
|
||||
}
|
||||
else if (val->type == T_QUAD) {
|
||||
ipv4_used = 1; key = val->val.i;
|
||||
}
|
||||
else if (val->type == T_IP) {
|
||||
ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
|
||||
}
|
||||
else
|
||||
@@ -254,7 +261,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
|
||||
IF, THEN, ELSE, CASE,
|
||||
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, IFNAME, IFINDEX,
|
||||
PREFERENCE,
|
||||
LEN,
|
||||
DEFINED,
|
||||
ADD, DELETE, CONTAINS, RESET,
|
||||
@@ -329,8 +337,8 @@ type:
|
||||
|
||||
one_decl:
|
||||
type SYM {
|
||||
struct f_val * val = cfg_alloc(sizeof(struct f_val));
|
||||
val->type = $1;
|
||||
struct f_val * val = cfg_alloc(sizeof(struct f_val));
|
||||
val->type = T_VOID;
|
||||
$2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
|
||||
DBG( "New variable %s type %x\n", $2->name, $1 );
|
||||
$2->aux2 = NULL;
|
||||
@@ -661,49 +669,28 @@ function_call:
|
||||
symbol:
|
||||
SYM {
|
||||
$$ = f_new_inst();
|
||||
switch ($1->class) {
|
||||
case SYM_NUMBER:
|
||||
$$ = f_new_inst();
|
||||
$$->code = 'c';
|
||||
$$->aux = T_INT;
|
||||
$$->a2.i = $1->aux;
|
||||
break;
|
||||
case SYM_IPA:
|
||||
{ NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; val->type = T_IP; val->val.px.ip = * (ip_addr *) ($1->def); }
|
||||
break;
|
||||
case SYM_VARIABLE | T_BOOL:
|
||||
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:
|
||||
case SYM_VARIABLE | T_PREFIX_SET:
|
||||
case SYM_VARIABLE | T_SET:
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
cf_error("%s: variable expected.", $1->name );
|
||||
|
||||
switch ($1->class & 0xff00) {
|
||||
case SYM_CONSTANT: $$->code = 'C'; break;
|
||||
case SYM_VARIABLE: $$->code = 'V'; break;
|
||||
default: cf_error("%s: variable expected.", $1->name);
|
||||
}
|
||||
|
||||
$$->a1.p = $1->def;
|
||||
$$->a2.p = $1->name;
|
||||
}
|
||||
|
||||
static_attr:
|
||||
FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, from); $$->a1.i = 1; }
|
||||
|
||||
| GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); $$->a1.i = 1; }
|
||||
| NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = 0x12345678; /* This is actually ok - T_PREFIX is special-cased. */ }
|
||||
| PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = 0x12345678; /* T_STRING is also special-cased. */ }
|
||||
| SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, source); }
|
||||
| SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = OFFSETOF(struct rta, scope); $$->a1.i = 1; }
|
||||
| CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = OFFSETOF(struct rta, cast); }
|
||||
| DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = OFFSETOF(struct rta, dest); $$->a1.i = 1; }
|
||||
FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; }
|
||||
| GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; }
|
||||
| NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = SA_NET; }
|
||||
| PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; }
|
||||
| SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; }
|
||||
| SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; }
|
||||
| CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; }
|
||||
| DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; }
|
||||
| IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; }
|
||||
| IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; }
|
||||
;
|
||||
|
||||
term:
|
||||
|
||||
514
filter/filter.c
514
filter/filter.c
@@ -58,79 +58,54 @@ adata_empty(struct linpool *pool, int l)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2)
|
||||
{
|
||||
while (1) {
|
||||
if ((!m1) || (!m2))
|
||||
return !((!m1) && (!m2));
|
||||
|
||||
/* FIXME: buggy, should return -1, 0, 1; but it doesn't matter */
|
||||
if ((m1->kind != m2->kind) || (m1->val != m2->val)) return 1;
|
||||
m1 = m1->next;
|
||||
m2 = m2->next;
|
||||
}
|
||||
}
|
||||
|
||||
u32 f_eval_asn(struct f_inst *expr);
|
||||
|
||||
static void
|
||||
pm_format(struct f_path_mask *p, byte *buf, unsigned int size)
|
||||
pm_format(struct f_path_mask *p, buffer *buf)
|
||||
{
|
||||
byte *end = buf + size - 16;
|
||||
buffer_puts(buf, "[= ");
|
||||
|
||||
while (p)
|
||||
{
|
||||
switch(p->kind)
|
||||
{
|
||||
if (buf > end)
|
||||
{
|
||||
strcpy(buf, " ...");
|
||||
return;
|
||||
}
|
||||
case PM_ASN:
|
||||
buffer_print(buf, "%u ", p->val);
|
||||
break;
|
||||
|
||||
switch(p->kind)
|
||||
{
|
||||
case PM_ASN:
|
||||
buf += bsprintf(buf, " %u", p->val);
|
||||
break;
|
||||
case PM_QUESTION:
|
||||
buffer_puts(buf, "? ");
|
||||
break;
|
||||
|
||||
case PM_QUESTION:
|
||||
buf += bsprintf(buf, " ?");
|
||||
break;
|
||||
case PM_ASTERISK:
|
||||
buffer_puts(buf, "* ");
|
||||
break;
|
||||
|
||||
case PM_ASTERISK:
|
||||
buf += bsprintf(buf, " *");
|
||||
break;
|
||||
|
||||
case PM_ASN_EXPR:
|
||||
buf += bsprintf(buf, " %u", f_eval_asn((struct f_inst *) p->val));
|
||||
break;
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
case PM_ASN_EXPR:
|
||||
buffer_print(buf, "%u ", f_eval_asn((struct f_inst *) p->val));
|
||||
break;
|
||||
}
|
||||
|
||||
*buf = 0;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
buffer_puts(buf, "=]");
|
||||
}
|
||||
|
||||
static inline int int_cmp(int i1, int i2)
|
||||
static inline int
|
||||
int_cmp(int i1, int i2)
|
||||
{
|
||||
if (i1 == i2) return 0;
|
||||
if (i1 < i2) return -1;
|
||||
else return 1;
|
||||
return (i1 > i2) - (i1 < i2);
|
||||
}
|
||||
|
||||
static inline int uint_cmp(unsigned int i1, unsigned int i2)
|
||||
static inline int
|
||||
uint_cmp(uint i1, uint i2)
|
||||
{
|
||||
if (i1 == i2) return 0;
|
||||
if (i1 < i2) return -1;
|
||||
else return 1;
|
||||
return (int)(i1 > i2) - (int)(i1 < i2);
|
||||
}
|
||||
|
||||
static inline int u64_cmp(u64 i1, u64 i2)
|
||||
static inline int
|
||||
u64_cmp(u64 i1, u64 i2)
|
||||
{
|
||||
if (i1 == i2) return 0;
|
||||
if (i1 < i2) return -1;
|
||||
else return 1;
|
||||
return (int)(i1 > i2) - (int)(i1 < i2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,23 +113,21 @@ static inline int u64_cmp(u64 i1, u64 i2)
|
||||
* @v1: first value
|
||||
* @v2: second value
|
||||
*
|
||||
* Compares two values and returns -1, 0, 1 on <, =, > or 999 on error.
|
||||
* Tree module relies on this giving consistent results so that it can
|
||||
* build balanced trees.
|
||||
* Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
|
||||
* error. Tree module relies on this giving consistent results so
|
||||
* that it can be used for building balanced trees.
|
||||
*/
|
||||
int
|
||||
val_compare(struct f_val v1, struct f_val v2)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((v1.type == T_VOID) && (v2.type == T_VOID))
|
||||
return 0;
|
||||
if (v1.type == T_VOID) /* Hack for else */
|
||||
return -1;
|
||||
if (v2.type == T_VOID)
|
||||
return 1;
|
||||
|
||||
if (v1.type != v2.type) {
|
||||
if (v1.type == T_VOID) /* Hack for else */
|
||||
return -1;
|
||||
if (v2.type == T_VOID)
|
||||
return 1;
|
||||
|
||||
#ifndef IPV6
|
||||
/* IP->Quad implicit conversion */
|
||||
if ((v1.type == T_QUAD) && (v2.type == T_IP))
|
||||
@@ -166,7 +139,10 @@ val_compare(struct f_val v1, struct f_val v2)
|
||||
debug( "Types do not match in val_compare\n" );
|
||||
return CMP_ERROR;
|
||||
}
|
||||
|
||||
switch (v1.type) {
|
||||
case T_VOID:
|
||||
return 0;
|
||||
case T_ENUM:
|
||||
case T_INT:
|
||||
case T_BOOL:
|
||||
@@ -181,25 +157,63 @@ val_compare(struct f_val v1, struct f_val v2)
|
||||
case T_PREFIX:
|
||||
if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip))
|
||||
return rc;
|
||||
if (v1.val.px.len < v2.val.px.len)
|
||||
return -1;
|
||||
if (v1.val.px.len > v2.val.px.len)
|
||||
return 1;
|
||||
return 0;
|
||||
case T_PATH_MASK:
|
||||
return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
|
||||
return int_cmp(v1.val.px.len, v2.val.px.len);
|
||||
case T_STRING:
|
||||
return strcmp(v1.val.s, v2.val.s);
|
||||
default:
|
||||
debug( "Compare of unknown entities: %x\n", v1.type );
|
||||
return CMP_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tree_compare(const void *p1, const void *p2)
|
||||
static int
|
||||
pm_path_same(struct f_path_mask *m1, struct f_path_mask *m2)
|
||||
{
|
||||
return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
|
||||
while (m1 && m2)
|
||||
{
|
||||
if ((m1->kind != m2->kind) || (m1->val != m2->val))
|
||||
return 0;
|
||||
|
||||
m1 = m1->next;
|
||||
m2 = m2->next;
|
||||
}
|
||||
|
||||
return !m1 && !m2;
|
||||
}
|
||||
|
||||
/**
|
||||
* val_same - compare two values
|
||||
* @v1: first value
|
||||
* @v2: second value
|
||||
*
|
||||
* Compares two values and returns 1 if they are same and 0 if not.
|
||||
* Comparison of values of different types is valid and returns 0.
|
||||
*/
|
||||
int
|
||||
val_same(struct f_val v1, struct f_val v2)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = val_compare(v1, v2);
|
||||
if (rc != CMP_ERROR)
|
||||
return !rc;
|
||||
|
||||
if (v1.type != v2.type)
|
||||
return 0;
|
||||
|
||||
switch (v1.type) {
|
||||
case T_PATH_MASK:
|
||||
return pm_path_same(v1.val.path_mask, v2.val.path_mask);
|
||||
case T_PATH:
|
||||
case T_CLIST:
|
||||
case T_ECLIST:
|
||||
return adata_same(v1.val.ad, v2.val.ad);
|
||||
case T_SET:
|
||||
return same_tree(v1.val.t, v2.val.t);
|
||||
case T_PREFIX_SET:
|
||||
return trie_same(v1.val.ti, v2.val.ti);
|
||||
default:
|
||||
bug("Invalid type in val_same(): %x", v1.type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -220,39 +234,6 @@ fprefix_get_bounds(struct f_prefix *px, int *l, int *h)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* val_simple_in_range - check if @v1 ~ @v2 for everything except sets
|
||||
*/
|
||||
static int
|
||||
val_simple_in_range(struct f_val v1, struct f_val v2)
|
||||
{
|
||||
if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
|
||||
return as_path_match(v1.val.ad, v2.val.path_mask);
|
||||
if ((v1.type == T_INT) && (v2.type == T_PATH))
|
||||
return as_path_is_member(v2.val.ad, v1.val.i);
|
||||
|
||||
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
|
||||
return int_set_contains(v2.val.ad, v1.val.i);
|
||||
#ifndef IPV6
|
||||
/* IP->Quad implicit conversion */
|
||||
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);
|
||||
|
||||
if ((v1.type == T_IP) && (v2.type == T_PREFIX))
|
||||
return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
|
||||
|
||||
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
|
||||
return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
|
||||
|
||||
return CMP_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
clist_set_type(struct f_tree *set, struct f_val *v)
|
||||
{
|
||||
@@ -396,103 +377,86 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
|
||||
* @v1: element
|
||||
* @v2: set
|
||||
*
|
||||
* Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see
|
||||
* |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early).
|
||||
* Checks if @v1 is element (|~| operator) of @v2.
|
||||
*/
|
||||
static int
|
||||
val_in_range(struct f_val v1, struct f_val v2)
|
||||
{
|
||||
int res;
|
||||
if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
|
||||
return as_path_match(v1.val.ad, v2.val.path_mask);
|
||||
|
||||
res = val_simple_in_range(v1, v2);
|
||||
if ((v1.type == T_INT) && (v2.type == T_PATH))
|
||||
return as_path_contains(v2.val.ad, v1.val.i, 1);
|
||||
|
||||
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
|
||||
return int_set_contains(v2.val.ad, v1.val.i);
|
||||
#ifndef IPV6
|
||||
/* IP->Quad implicit conversion */
|
||||
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);
|
||||
|
||||
if ((v1.type == T_IP) && (v2.type == T_PREFIX))
|
||||
return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
|
||||
|
||||
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
|
||||
return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
|
||||
|
||||
if (res != CMP_ERROR)
|
||||
return res;
|
||||
|
||||
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
|
||||
return trie_match_fprefix(v2.val.ti, &v1.val.px);
|
||||
|
||||
if ((v1.type == T_CLIST) && (v2.type == T_SET))
|
||||
if (v2.type != T_SET)
|
||||
return CMP_ERROR;
|
||||
|
||||
/* With integrated Quad<->IP implicit conversion */
|
||||
if ((v1.type == v2.val.t->from.type) ||
|
||||
((IP_VERSION == 4) && (v1.type == T_QUAD) && (v2.val.t->from.type == T_IP)))
|
||||
return !!find_tree(v2.val.t, v1);
|
||||
|
||||
if (v1.type == T_CLIST)
|
||||
return clist_match_set(v1.val.ad, v2.val.t);
|
||||
|
||||
if ((v1.type == T_ECLIST) && (v2.type == T_SET))
|
||||
if (v1.type == T_ECLIST)
|
||||
return eclist_match_set(v1.val.ad, v2.val.t);
|
||||
|
||||
if (v2.type == T_SET)
|
||||
switch (v1.type) {
|
||||
case T_ENUM:
|
||||
case T_INT:
|
||||
case T_PAIR:
|
||||
case T_QUAD:
|
||||
case T_IP:
|
||||
case T_EC:
|
||||
{
|
||||
struct f_tree *n;
|
||||
n = find_tree(v2.val.t, v1);
|
||||
if (!n)
|
||||
return 0;
|
||||
return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */
|
||||
}
|
||||
}
|
||||
if (v1.type == T_PATH)
|
||||
return as_path_match_set(v1.val.ad, v2.val.t);
|
||||
|
||||
return CMP_ERROR;
|
||||
}
|
||||
|
||||
static void val_print(struct f_val v);
|
||||
|
||||
static void
|
||||
tree_node_print(struct f_tree *t, char **sep)
|
||||
{
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
tree_node_print(t->left, sep);
|
||||
|
||||
logn(*sep);
|
||||
val_print(t->from);
|
||||
if (val_compare(t->from, t->to) != 0)
|
||||
{
|
||||
logn( ".." );
|
||||
val_print(t->to);
|
||||
}
|
||||
*sep = ", ";
|
||||
|
||||
tree_node_print(t->right, sep);
|
||||
}
|
||||
|
||||
static void
|
||||
tree_print(struct f_tree *t)
|
||||
{
|
||||
char *sep = "";
|
||||
logn( "[" );
|
||||
tree_node_print(t, &sep);
|
||||
logn( "] " );
|
||||
}
|
||||
|
||||
/*
|
||||
* val_print - format filter value
|
||||
* val_format - format filter value
|
||||
*/
|
||||
static void
|
||||
val_print(struct f_val v)
|
||||
void
|
||||
val_format(struct f_val v, buffer *buf)
|
||||
{
|
||||
char buf2[1024];
|
||||
switch (v.type) {
|
||||
case T_VOID: logn("(void)"); return;
|
||||
case T_BOOL: logn(v.val.i ? "TRUE" : "FALSE"); return;
|
||||
case T_INT: logn("%d", v.val.i); return;
|
||||
case T_STRING: logn("%s", v.val.s); return;
|
||||
case T_IP: logn("%I", v.val.px.ip); 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_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;
|
||||
switch (v.type)
|
||||
{
|
||||
case T_VOID: buffer_puts(buf, "(void)"); return;
|
||||
case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return;
|
||||
case T_INT: buffer_print(buf, "%d", v.val.i); return;
|
||||
case T_STRING: buffer_print(buf, "%s", v.val.s); return;
|
||||
case T_IP: buffer_print(buf, "%I", v.val.px.ip); return;
|
||||
case T_PREFIX: buffer_print(buf, "%I/%d", v.val.px.ip, v.val.px.len); return;
|
||||
case T_PAIR: buffer_print(buf, "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff); return;
|
||||
case T_QUAD: buffer_print(buf, "%R", v.val.i); return;
|
||||
case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return;
|
||||
case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
|
||||
case T_SET: tree_format(v.val.t, buf); return;
|
||||
case T_ENUM: buffer_print(buf, "(enum %x)%d", v.type, v.val.i); return;
|
||||
case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
|
||||
case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
|
||||
case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
|
||||
case T_PATH_MASK: pm_format(v.val.path_mask, buf); return;
|
||||
default: buffer_print(buf, "[unknown type %x]", v.type); return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,6 +464,7 @@ static struct rte **f_rte;
|
||||
static struct rta *f_old_rta;
|
||||
static struct ea_list **f_tmp_attrs;
|
||||
static struct linpool *f_pool;
|
||||
static struct buffer f_buf;
|
||||
static int f_flags;
|
||||
|
||||
static inline void f_rte_cow(void)
|
||||
@@ -555,6 +520,8 @@ static struct rate_limit rl_runtime_err;
|
||||
#define TWOARGS_C TWOARGS \
|
||||
if (v1.type != v2.type) \
|
||||
runtime( "Can't operate with values of incompatible types" );
|
||||
#define ACCESS_RTE \
|
||||
do { if (!f_rte) runtime("No route to access"); } while (0)
|
||||
|
||||
/**
|
||||
* interpret
|
||||
@@ -622,9 +589,6 @@ interpret(struct f_inst *what)
|
||||
case T_VOID: runtime( "Can't operate with values of type void" );
|
||||
case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
|
||||
res.val.i = v1.val.i / v2.val.i; break;
|
||||
case T_IP: if (v2.type != T_INT)
|
||||
runtime( "Incompatible types in / operator" );
|
||||
break;
|
||||
default: runtime( "Usage of unknown type" );
|
||||
}
|
||||
break;
|
||||
@@ -717,8 +681,15 @@ interpret(struct f_inst *what)
|
||||
res.val.i = (x); \
|
||||
break;
|
||||
|
||||
case P('!','='): COMPARE(i!=0);
|
||||
case P('=','='): COMPARE(i==0);
|
||||
#define SAME(x) \
|
||||
TWOARGS; \
|
||||
i = val_same(v1, v2); \
|
||||
res.type = T_BOOL; \
|
||||
res.val.i = (x); \
|
||||
break;
|
||||
|
||||
case P('!','='): SAME(!i);
|
||||
case P('=','='): SAME(i);
|
||||
case '<': COMPARE(i==-1);
|
||||
case P('<','='): COMPARE(i!=1);
|
||||
|
||||
@@ -782,7 +753,7 @@ interpret(struct f_inst *what)
|
||||
break;
|
||||
case 'p':
|
||||
ONEARG;
|
||||
val_print(v1);
|
||||
val_format(v1, &f_buf);
|
||||
break;
|
||||
case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
|
||||
ONEARG;
|
||||
@@ -800,7 +771,7 @@ interpret(struct f_inst *what)
|
||||
case P('p',','):
|
||||
ONEARG;
|
||||
if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
|
||||
log_commit(*L_INFO);
|
||||
log_commit(*L_INFO, &f_buf);
|
||||
|
||||
switch (what->a2.i) {
|
||||
case F_QUITBIRD:
|
||||
@@ -821,62 +792,83 @@ interpret(struct f_inst *what)
|
||||
break;
|
||||
case 'a': /* rta access */
|
||||
{
|
||||
ACCESS_RTE;
|
||||
struct rta *rta = (*f_rte)->attrs;
|
||||
res.type = what->aux;
|
||||
switch(res.type) {
|
||||
case T_IP:
|
||||
res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
|
||||
break;
|
||||
case T_ENUM:
|
||||
res.val.i = * ((char *) rta + what->a2.i);
|
||||
break;
|
||||
case T_STRING: /* Warning: this is a special case for proto attribute */
|
||||
res.val.s = rta->src->proto->name;
|
||||
break;
|
||||
case T_PREFIX: /* Warning: this works only for prefix of network */
|
||||
{
|
||||
res.val.px.ip = (*f_rte)->net->n.prefix;
|
||||
res.val.px.len = (*f_rte)->net->n.pxlen;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (what->a2.i)
|
||||
{
|
||||
case SA_FROM: res.val.px.ip = rta->from; break;
|
||||
case SA_GW: res.val.px.ip = rta->gw; break;
|
||||
case SA_NET: res.val.px.ip = (*f_rte)->net->n.prefix;
|
||||
res.val.px.len = (*f_rte)->net->n.pxlen; break;
|
||||
case SA_PROTO: res.val.s = rta->src->proto->name; break;
|
||||
case SA_SOURCE: res.val.i = rta->source; break;
|
||||
case SA_SCOPE: res.val.i = rta->scope; break;
|
||||
case SA_CAST: res.val.i = rta->cast; break;
|
||||
case SA_DEST: res.val.i = rta->dest; break;
|
||||
case SA_IFNAME: res.val.s = rta->iface ? rta->iface->name : ""; break;
|
||||
case SA_IFINDEX: res.val.i = rta->iface ? rta->iface->index : 0; break;
|
||||
|
||||
default:
|
||||
bug( "Invalid type for rta access (%x)", res.type );
|
||||
bug("Invalid static attribute access (%x)", res.type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case P('a','S'):
|
||||
ACCESS_RTE;
|
||||
ONEARG;
|
||||
if (what->aux != v1.type)
|
||||
runtime( "Attempt to set static attribute to incompatible type" );
|
||||
|
||||
f_rta_cow();
|
||||
{
|
||||
struct rta *rta = (*f_rte)->attrs;
|
||||
switch (what->aux) {
|
||||
|
||||
case T_IP:
|
||||
* (ip_addr *) ((char *) rta + what->a2.i) = v1.val.px.ip;
|
||||
switch (what->a2.i)
|
||||
{
|
||||
case SA_FROM:
|
||||
rta->from = v1.val.px.ip;
|
||||
break;
|
||||
|
||||
case T_ENUM_SCOPE:
|
||||
case SA_GW:
|
||||
{
|
||||
ip_addr ip = v1.val.px.ip;
|
||||
neighbor *n = neigh_find(rta->src->proto, &ip, 0);
|
||||
if (!n || (n->scope == SCOPE_HOST))
|
||||
runtime( "Invalid gw address" );
|
||||
|
||||
rta->dest = RTD_ROUTER;
|
||||
rta->gw = ip;
|
||||
rta->iface = n->iface;
|
||||
rta->nexthops = NULL;
|
||||
rta->hostentry = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case SA_SCOPE:
|
||||
rta->scope = v1.val.i;
|
||||
break;
|
||||
|
||||
case T_ENUM_RTD:
|
||||
case SA_DEST:
|
||||
i = v1.val.i;
|
||||
if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
|
||||
runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
|
||||
|
||||
rta->dest = i;
|
||||
rta->gw = IPA_NONE;
|
||||
rta->iface = NULL;
|
||||
rta->nexthops = NULL;
|
||||
rta->hostentry = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
bug( "Unknown type in set of static attribute" );
|
||||
bug("Invalid static attribute access (%x)", res.type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case P('e','a'): /* Access to extended attributes */
|
||||
ACCESS_RTE;
|
||||
{
|
||||
eattr *e = NULL;
|
||||
if (!(f_flags & FF_FORCE_TMPATTR))
|
||||
@@ -944,6 +936,7 @@ interpret(struct f_inst *what)
|
||||
}
|
||||
break;
|
||||
case P('e','S'):
|
||||
ACCESS_RTE;
|
||||
ONEARG;
|
||||
{
|
||||
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
|
||||
@@ -956,11 +949,25 @@ interpret(struct f_inst *what)
|
||||
l->attrs[0].type = what->aux | EAF_ORIGINATED;
|
||||
switch (what->aux & EAF_TYPE_MASK) {
|
||||
case EAF_TYPE_INT:
|
||||
case EAF_TYPE_ROUTER_ID:
|
||||
if (v1.type != T_INT)
|
||||
runtime( "Setting int attribute to non-int value" );
|
||||
l->attrs[0].u.data = v1.val.i;
|
||||
break;
|
||||
|
||||
case EAF_TYPE_ROUTER_ID:
|
||||
#ifndef IPV6
|
||||
/* IP->Quad implicit conversion */
|
||||
if (v1.type == T_IP) {
|
||||
l->attrs[0].u.data = ipa_to_u32(v1.val.px.ip);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* T_INT for backward compatibility */
|
||||
if ((v1.type != T_QUAD) && (v1.type != T_INT))
|
||||
runtime( "Setting quad attribute to non-quad value" );
|
||||
l->attrs[0].u.data = v1.val.i;
|
||||
break;
|
||||
|
||||
case EAF_TYPE_OPAQUE:
|
||||
runtime( "Setting opaque attribute is not allowed" );
|
||||
break;
|
||||
@@ -1007,10 +1014,12 @@ interpret(struct f_inst *what)
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
ACCESS_RTE;
|
||||
res.type = T_INT;
|
||||
res.val.i = (*f_rte)->pref;
|
||||
break;
|
||||
case P('P','S'):
|
||||
ACCESS_RTE;
|
||||
ONEARG;
|
||||
if (v1.type != T_INT)
|
||||
runtime( "Can't set preference to non-integer" );
|
||||
@@ -1025,7 +1034,9 @@ interpret(struct f_inst *what)
|
||||
switch(v1.type) {
|
||||
case T_PREFIX: res.val.i = v1.val.px.len; break;
|
||||
case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
|
||||
default: runtime( "Prefix or path expected" );
|
||||
case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break;
|
||||
case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
|
||||
default: runtime( "Prefix, path, clist or eclist expected" );
|
||||
}
|
||||
break;
|
||||
case P('c','p'): /* Convert prefix to ... */
|
||||
@@ -1124,7 +1135,34 @@ interpret(struct f_inst *what)
|
||||
|
||||
case P('C','a'): /* (Extended) Community list add or delete */
|
||||
TWOARGS;
|
||||
if (v1.type == T_CLIST)
|
||||
if (v1.type == T_PATH)
|
||||
{
|
||||
struct f_tree *set = NULL;
|
||||
u32 key = 0;
|
||||
int pos;
|
||||
|
||||
if (v2.type == T_INT)
|
||||
key = v2.val.i;
|
||||
else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
|
||||
set = v2.val.t;
|
||||
else
|
||||
runtime("Can't delete non-integer (set)");
|
||||
|
||||
switch (what->aux)
|
||||
{
|
||||
case 'a': runtime("Can't add to path");
|
||||
case 'd': pos = 0; break;
|
||||
case 'f': pos = 1; break;
|
||||
default: bug("unknown Ca operation");
|
||||
}
|
||||
|
||||
if (pos && !set)
|
||||
runtime("Can't filter integer");
|
||||
|
||||
res.type = T_PATH;
|
||||
res.val.ad = as_path_filter(f_pool, v1.val.ad, set, key, pos);
|
||||
}
|
||||
else if (v1.type == T_CLIST)
|
||||
{
|
||||
/* Community (or cluster) list */
|
||||
struct f_val dummy;
|
||||
@@ -1232,6 +1270,7 @@ interpret(struct f_inst *what)
|
||||
}
|
||||
else
|
||||
{
|
||||
ACCESS_RTE;
|
||||
v1.val.px.ip = (*f_rte)->net->n.prefix;
|
||||
v1.val.px.len = (*f_rte)->net->n.pxlen;
|
||||
|
||||
@@ -1343,10 +1382,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
A2_SAME;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
|
||||
|
||||
case 'C':
|
||||
if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
|
||||
return 0;
|
||||
@@ -1418,6 +1459,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
int
|
||||
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
|
||||
{
|
||||
if (filter == FILTER_ACCEPT)
|
||||
return F_ACCEPT;
|
||||
|
||||
if (filter == FILTER_REJECT)
|
||||
return F_REJECT;
|
||||
|
||||
int rte_cow = ((*rte)->flags & REF_COW);
|
||||
DBG( "Running filter `%s'...", filter->name );
|
||||
|
||||
@@ -1427,7 +1474,8 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
|
||||
f_pool = tmp_pool;
|
||||
f_flags = flags;
|
||||
|
||||
log_reset();
|
||||
LOG_BUFFER_INIT(f_buf);
|
||||
|
||||
struct f_val res = interpret(filter->root);
|
||||
|
||||
if (f_old_rta) {
|
||||
@@ -1458,22 +1506,28 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
|
||||
return res.val.i;
|
||||
}
|
||||
|
||||
struct f_val
|
||||
f_eval(struct f_inst *expr, struct linpool *tmp_pool)
|
||||
{
|
||||
f_flags = 0;
|
||||
f_tmp_attrs = NULL;
|
||||
f_rte = NULL;
|
||||
f_pool = tmp_pool;
|
||||
|
||||
LOG_BUFFER_INIT(f_buf);
|
||||
|
||||
return interpret(expr);
|
||||
}
|
||||
|
||||
int
|
||||
f_eval_int(struct f_inst *expr)
|
||||
{
|
||||
/* Called independently in parse-time to eval expressions */
|
||||
struct f_val res;
|
||||
|
||||
f_flags = 0;
|
||||
f_tmp_attrs = NULL;
|
||||
f_rte = NULL;
|
||||
f_pool = cfg_mem;
|
||||
|
||||
log_reset();
|
||||
res = interpret(expr);
|
||||
struct f_val res = f_eval(expr, cfg_mem);
|
||||
|
||||
if (res.type != T_INT)
|
||||
cf_error("Integer expression expected");
|
||||
|
||||
return res.val.i;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,12 +78,13 @@ struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, s
|
||||
struct f_tree *build_tree(struct f_tree *);
|
||||
struct f_tree *find_tree(struct f_tree *t, struct f_val val);
|
||||
int same_tree(struct f_tree *t1, struct f_tree *t2);
|
||||
void tree_format(struct f_tree *t, buffer *buf);
|
||||
|
||||
struct f_trie *f_new_trie(linpool *lp);
|
||||
void trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h);
|
||||
int trie_match_prefix(struct f_trie *t, ip_addr px, int plen);
|
||||
int trie_same(struct f_trie *t1, struct f_trie *t2);
|
||||
void trie_print(struct f_trie *t);
|
||||
void trie_format(struct f_trie *t, buffer *buf);
|
||||
|
||||
void fprefix_get_bounds(struct f_prefix *px, int *l, int *h);
|
||||
|
||||
@@ -106,6 +107,7 @@ struct ea_list;
|
||||
struct rte;
|
||||
|
||||
int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags);
|
||||
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
|
||||
int f_eval_int(struct f_inst *expr);
|
||||
u32 f_eval_asn(struct f_inst *expr);
|
||||
|
||||
@@ -115,7 +117,10 @@ int filter_same(struct filter *new, struct filter *old);
|
||||
int i_same(struct f_inst *f1, struct f_inst *f2);
|
||||
|
||||
int val_compare(struct f_val v1, struct f_val v2);
|
||||
int tree_compare(const void *p1, const void *p2);
|
||||
int val_same(struct f_val v1, struct f_val v2);
|
||||
|
||||
void val_format(struct f_val v, buffer *buf);
|
||||
|
||||
|
||||
#define F_NOP 0
|
||||
#define F_NONL 1
|
||||
@@ -169,6 +174,19 @@ int tree_compare(const void *p1, const void *p2);
|
||||
#define T_SET 0x80
|
||||
#define T_PREFIX_SET 0x81
|
||||
|
||||
|
||||
#define SA_FROM 1
|
||||
#define SA_GW 2
|
||||
#define SA_NET 3
|
||||
#define SA_PROTO 4
|
||||
#define SA_SOURCE 5
|
||||
#define SA_SCOPE 6
|
||||
#define SA_CAST 7
|
||||
#define SA_DEST 8
|
||||
#define SA_IFNAME 9
|
||||
#define SA_IFINDEX 10
|
||||
|
||||
|
||||
struct f_tree {
|
||||
struct f_tree *left, *right;
|
||||
struct f_val from, to;
|
||||
|
||||
@@ -95,16 +95,18 @@ eclist el2;
|
||||
p2 = prepend( p2, 3 );
|
||||
p2 = prepend( p2, 4 );
|
||||
print "Testing paths: ", p2;
|
||||
print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2;
|
||||
print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2, " ", p2 ~ [2, 10..20], " ", p2 ~ [4, 10..20];
|
||||
print "4 = ", p2.len;
|
||||
p2 = prepend( p2, 5 );
|
||||
print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2;
|
||||
print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2, " ", p2 ~ [8, 10..20],;
|
||||
print "Should be true: ", p2 ~ / ? 4 3 2 1 /, " ", p2, " ", / ? 4 3 2 1 /;
|
||||
print "Should be true: ", p2 ~ [= * 4 3 * 1 =], " ", p2, " ", [= * 4 3 * 1 =];
|
||||
print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4);
|
||||
print "Should be true: ", p2.len = 5, " ", p2.first = 5, " ", p2.last = 1;
|
||||
print "5 = ", p2.len;
|
||||
|
||||
print "Delete 3: ", delete(p2, 3);
|
||||
print "Filter 1-3: ", filter(p2, [1..3]);
|
||||
|
||||
pm1 = [= 1 2 * 3 4 5 =];
|
||||
p2 = prepend( + empty +, 5 );
|
||||
p2 = prepend( p2, 4 );
|
||||
@@ -113,6 +115,8 @@ eclist el2;
|
||||
p2 = prepend( p2, 2 );
|
||||
p2 = prepend( p2, 1 );
|
||||
print "Should be true: ", p2 ~ pm1, " ", p2, " ", pm1;
|
||||
print "Delete 3: ", delete(p2, 3);
|
||||
print "Delete 4-5: ", delete(p2, [4..5]);
|
||||
|
||||
l = - empty -;
|
||||
print "Should be false in this special case: ", l ~ [(*,*)];
|
||||
@@ -138,10 +142,10 @@ eclist el2;
|
||||
l = add( l, (3,5) );
|
||||
l2 = filter( l, [(3,*)] );
|
||||
l = delete( l, [(3,2..4)] );
|
||||
print "Community list (1,2) (3,1) (3,5) ", l;
|
||||
print "Community list (1,2) (3,1) (3,5) ", l, " len: ", l.len;
|
||||
l = add( l, (3,2) );
|
||||
l = add( l, (4,5) );
|
||||
print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l;
|
||||
print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l, " len: ", l.len;
|
||||
print "Should be true: ", l ~ [(*,2)], " ", l ~ [(*,5)], " ", l ~ [(*, one)];
|
||||
print "Should be false: ", l ~ [(*,3)], " ", l ~ [(*,(one+6))], " ", l ~ [(*, (one+one+one))];
|
||||
l = delete( l, [(*,(one+onef(3)))] );
|
||||
@@ -164,6 +168,7 @@ eclist el2;
|
||||
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;
|
||||
print "EC len: ", el.len;
|
||||
el = delete(el, (rt, 10, 20));
|
||||
el = delete(el, (rt, 10, 30));
|
||||
el = add(el, (unknown 2, ten, 1));
|
||||
@@ -240,6 +245,15 @@ int b;
|
||||
print "Defined: ", a, " ", b, " ", defined(b);
|
||||
}
|
||||
|
||||
define is1 = [ one, (2+1), (6-one), 8, 11, 15, 17, 19];
|
||||
define is2 = [(17+2), 17, 15, 11, 8, 5, 3, 2];
|
||||
define is3 = [5, 17, 2, 11, 8, 15, 3, 19];
|
||||
|
||||
define pxs2 = [ 10.0.0.0/16{8,12}, 20.0.0.0/16{24,28} ];
|
||||
|
||||
define ecs2 = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)];
|
||||
|
||||
|
||||
function __startup()
|
||||
int i;
|
||||
bool b;
|
||||
@@ -249,13 +263,11 @@ pair pp;
|
||||
quad qq;
|
||||
ec cc;
|
||||
int set is;
|
||||
int set is1;
|
||||
int set is2;
|
||||
int set is3;
|
||||
pair set ps;
|
||||
ec set ecs;
|
||||
ip set ips;
|
||||
prefix set pxs;
|
||||
string s;
|
||||
string st;
|
||||
{
|
||||
print "1a-a1 = 30: ", '1a-a1';
|
||||
print "Testing filter language:";
|
||||
@@ -272,6 +284,12 @@ string s;
|
||||
# if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; }
|
||||
if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok";
|
||||
is = [ 2, 3, 4, 7..11 ];
|
||||
|
||||
print "must be true: ", 1 = 1, " ", 1 != (0,1), " ", 1 != "a", " ", +empty+ = +empty+, " ", -empty- = -empty-, " ", --empty-- = --empty-- ,
|
||||
" ", [1,4..10,20] = [1,4..10,20] , " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 10.0.0.0/8{ 15 , 17 } ];
|
||||
print "must be false: ", 1 != 1, " ", 1 = (0,1), " ", 1 = "a", " ", +empty+ = -empty-, " ", -empty- = --empty--, " ", --empty-- = +empty+ ,
|
||||
" ", [1,2] = [1,3], " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 11.0.0.0/8{ 15 , 17 } ];
|
||||
|
||||
print " must be true: ", 1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ];
|
||||
print " data types; must be true: ", 1.2.3.4 = 1.2.3.4, ",", 1 ~ [1,2,3], ",", 5 ~ [1..20], ",", 10 ~ is, ",", 2 ~ [ 1, 2, 3 ], ",", 5 ~ [ 4 .. 7 ], ",", 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ], ",", 1.2.3.4 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ [ 1.0.0.0/8+ ];
|
||||
print " must be true: ", true && true, ",", true || false, ",", ! false && ! false && true, ",", 1 < 2 && 1 != 3, ",", true && true && ! false, ",", true || 1+"a", ",", !(false && 1+"a");
|
||||
@@ -279,11 +297,6 @@ string s;
|
||||
print " must be true: ", defined(1), ",", defined(1.2.3.4), ",", 1 != 2, ",", 1 <= 2;
|
||||
print " data types: must be false: ", 1 ~ [ 2, 3, 4 ], ",", 5 ~ is, ",", 1.2.3.4 ~ [ 1.2.3.3, 1.2.3.5 ], ",", (1,2) > (2,2), ",", (1,1) > (1,1), ",", 1.0.0.0/9 ~ [ 1.0.0.0/8- ], ",", 1.2.0.0/17 ~ [ 1.0.0.0/8{ 15 , 16 } ], ",", true && false;
|
||||
|
||||
is1 = [ 1, 5, 8, 11, 15, 17, 19];
|
||||
|
||||
is1 = [ one, (2+1), (6-one), 8, 11, 15, 17, 19];
|
||||
is2 = [(17+2), 17, 15, 11, 8, 5, 3, 2];
|
||||
is3 = [5, 17, 2, 11, 8, 15, 3, 19];
|
||||
|
||||
print " must be true: ", 1 ~ is1, " ", 3 ~ is1, " ", 5 ~ is1;
|
||||
print " must be true: ", (one+2) ~ is1, " ", 2 ~ is2, " ", 2 ~ is3;
|
||||
@@ -333,13 +346,14 @@ string s;
|
||||
|
||||
ecs = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)];
|
||||
print "EC set: ", ecs;
|
||||
print "EC set: ", ecs2;
|
||||
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*";
|
||||
st = "Hello";
|
||||
print "Testing string: ", st, " true: ", st ~ "Hell*", " false: ", st ~ "ell*";
|
||||
|
||||
b = true;
|
||||
print "Testing bool: ", b, ", ", !b;
|
||||
@@ -347,6 +361,12 @@ string s;
|
||||
if ( b = true ) then print "Testing bool comparison b = true: ", b;
|
||||
else { print "*** FAIL: TRUE test failed" ; quitbird; }
|
||||
|
||||
ips = [ 1.1.1.0 .. 1.1.1.255, 1.2.2.2];
|
||||
print "Testing IP sets: ";
|
||||
print ips;
|
||||
print " must be true: ", 1.1.1.0 ~ ips, ",", 1.1.1.100 ~ ips, ",", 1.2.2.2 ~ ips;
|
||||
print " must be false: ", 1.1.0.255 ~ ips, ",", 1.1.2.0 ~ ips, ",", 1.2.2.3 ~ ips, ",", 192.168.1.1 ~ ips;
|
||||
|
||||
pxs = [ 1.2.0.0/16, 1.4.0.0/16+];
|
||||
print "Testing prefix sets: ";
|
||||
print pxs;
|
||||
@@ -354,6 +374,7 @@ string s;
|
||||
print " must be false: ", 1.1.0.0/16 ~ pxs, ",", 1.3.0.0/16 ~ pxs, ",", 1.2.0.0/15 ~ pxs, ",", 1.2.0.0/17 ~ pxs, ",",
|
||||
1.2.0.0/32 ~ pxs, ",", 1.4.0.0/15 ~ pxs;
|
||||
|
||||
test_pxset(pxs2);
|
||||
test_pxset([ 10.0.0.0/16{8,12}, 20.0.0.0/16{24,28} ]);
|
||||
print "What will this do? ", [ 1, 2, 1, 1, 1, 3, 4, 1, 1, 1, 5 ];
|
||||
|
||||
@@ -372,6 +393,9 @@ string s;
|
||||
|
||||
print "1.2.3.4 = ", onetwo;
|
||||
|
||||
i = 4200000000;
|
||||
print "4200000000 = ", i, " false: ", i = 4200000000, " ", i > 4100000000, " false: ", i > 4250000000;
|
||||
|
||||
test_undef(2);
|
||||
test_undef(3);
|
||||
test_undef(2);
|
||||
|
||||
@@ -53,6 +53,11 @@ build_tree_rec(struct f_tree **buf, int l, int h)
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
tree_compare(const void *p1, const void *p2)
|
||||
{
|
||||
return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
|
||||
}
|
||||
|
||||
/**
|
||||
* build_tree
|
||||
@@ -132,3 +137,37 @@ same_tree(struct f_tree *t1, struct f_tree *t2)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
tree_node_format(struct f_tree *t, buffer *buf)
|
||||
{
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
tree_node_format(t->left, buf);
|
||||
|
||||
val_format(t->from, buf);
|
||||
if (val_compare(t->from, t->to) != 0)
|
||||
{
|
||||
buffer_puts(buf, "..");
|
||||
val_format(t->to, buf);
|
||||
}
|
||||
buffer_puts(buf, ", ");
|
||||
|
||||
tree_node_format(t->right, buf);
|
||||
}
|
||||
|
||||
void
|
||||
tree_format(struct f_tree *t, buffer *buf)
|
||||
{
|
||||
buffer_puts(buf, "[");
|
||||
|
||||
tree_node_format(t, buf);
|
||||
|
||||
/* Undo last separator */
|
||||
if (buf->pos[-1] != '[')
|
||||
buf->pos -= 2;
|
||||
|
||||
buffer_puts(buf, "]");
|
||||
}
|
||||
|
||||
@@ -265,37 +265,37 @@ trie_same(struct f_trie *t1, struct f_trie *t2)
|
||||
}
|
||||
|
||||
static void
|
||||
trie_node_print(struct f_trie_node *t, char **sep)
|
||||
trie_node_format(struct f_trie_node *t, buffer *buf)
|
||||
{
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
if (ipa_nonzero(t->accept))
|
||||
{
|
||||
logn("%s%I/%d{%I}", *sep, t->addr, t->plen, t->accept);
|
||||
*sep = ", ";
|
||||
}
|
||||
buffer_print(buf, "%I/%d{%I}, ", t->addr, t->plen, t->accept);
|
||||
|
||||
trie_node_print(t->c[0], sep);
|
||||
trie_node_print(t->c[1], sep);
|
||||
trie_node_format(t->c[0], buf);
|
||||
trie_node_format(t->c[1], buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* trie_print
|
||||
* @t: trie to be printed
|
||||
* trie_format
|
||||
* @t: trie to be formatted
|
||||
* @buf: destination buffer
|
||||
*
|
||||
* Prints the trie to the log buffer.
|
||||
* Prints the trie to the supplied buffer.
|
||||
*/
|
||||
void
|
||||
trie_print(struct f_trie *t)
|
||||
trie_format(struct f_trie *t, buffer *buf)
|
||||
{
|
||||
char *sep = "";
|
||||
logn("[");
|
||||
buffer_puts(buf, "[");
|
||||
|
||||
if (t->zero)
|
||||
{
|
||||
logn("0.0.0.0/0");
|
||||
sep = ", ";
|
||||
}
|
||||
trie_node_print(&t->root, &sep);
|
||||
logn("]");
|
||||
buffer_print(buf, "%I/%d", IPA_NONE, 0);
|
||||
trie_node_format(&t->root, buf);
|
||||
|
||||
/* Undo last separator */
|
||||
if (buf->pos[-1] != '[')
|
||||
buf->pos -= 2;
|
||||
|
||||
buffer_puts(buf, "]");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user