summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2013-11-23 11:50:34 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2013-11-23 11:50:34 +0100
commit736e143fa50607fcd88132291e96089b899af979 (patch)
treec0fcd5fb3174bae8a39b3a32dfe582b2ccb6df17 /filter
parent094d2bdb79e1ffa0a02761fd651aa0f0b6b0c585 (diff)
parent2b3d52aa421ae1c31e30107beefd82fddbb42854 (diff)
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
Diffstat (limited to 'filter')
-rw-r--r--filter/config.Y73
-rw-r--r--filter/filter.c510
-rw-r--r--filter/filter.h22
-rw-r--r--filter/test.conf56
-rw-r--r--filter/tree.c39
-rw-r--r--filter/trie.c38
6 files changed, 430 insertions, 308 deletions
diff --git a/filter/config.Y b/filter/config.Y
index 0eeb2ce1..04acfbab 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -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:
diff --git a/filter/filter.c b/filter/filter.c
index 7c883fff..ed8efd54 100644
--- a/filter/filter.c
+++ b/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;
- }
-
- switch(p->kind)
- {
- case PM_ASN:
- buf += bsprintf(buf, " %u", p->val);
- break;
-
- case PM_QUESTION:
- buf += bsprintf(buf, " ?");
- break;
+ case PM_ASN:
+ buffer_print(buf, "%u ", p->val);
+ break;
- case PM_ASTERISK:
- buf += bsprintf(buf, " *");
- break;
+ case PM_QUESTION:
+ buffer_puts(buf, "? ");
+ break;
- case PM_ASN_EXPR:
- buf += bsprintf(buf, " %u", f_eval_asn((struct f_inst *) p->val));
- break;
- }
+ case PM_ASTERISK:
+ buffer_puts(buf, "* ");
+ 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 (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_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_CLIST) && (v2.type == T_SET))
- return clist_match_set(v1.val.ad, v2.val.t);
+ if ((v1.type == T_EC) && (v2.type == T_ECLIST))
+ return ec_set_contains(v2.val.ad, v1.val.ec);
- if ((v1.type == T_ECLIST) && (v2.type == T_SET))
- return eclist_match_set(v1.val.ad, v2.val.t);
+ if ((v1.type == T_STRING) && (v2.type == T_STRING))
+ return patmatch(v2.val.s, v1.val.s);
- 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 */
- }
- }
- return CMP_ERROR;
-}
+ 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);
-static void val_print(struct f_val v);
+ 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);
-static void
-tree_node_print(struct f_tree *t, char **sep)
-{
- if (t == NULL)
- return;
+ if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
+ return trie_match_fprefix(v2.val.ti, &v1.val.px);
- tree_node_print(t->left, sep);
+ if (v2.type != T_SET)
+ return CMP_ERROR;
- logn(*sep);
- val_print(t->from);
- if (val_compare(t->from, t->to) != 0)
- {
- logn( ".." );
- val_print(t->to);
- }
- *sep = ", ";
+ /* 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);
- tree_node_print(t->right, sep);
-}
+ if (v1.type == T_CLIST)
+ return clist_match_set(v1.val.ad, v2.val.t);
-static void
-tree_print(struct f_tree *t)
-{
- char *sep = "";
- logn( "[" );
- tree_node_print(t, &sep);
- logn( "] " );
+ if (v1.type == T_ECLIST)
+ return eclist_match_set(v1.val.ad, v2.val.t);
+
+ if (v1.type == T_PATH)
+ return as_path_match_set(v1.val.ad, v2.val.t);
+
+ return CMP_ERROR;
}
/*
- * 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;
}
-int
-f_eval_int(struct f_inst *expr)
+struct f_val
+f_eval(struct f_inst *expr, struct linpool *tmp_pool)
{
- /* 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;
+ f_pool = tmp_pool;
+
+ LOG_BUFFER_INIT(f_buf);
+
+ return interpret(expr);
+}
- log_reset();
- res = interpret(expr);
+int
+f_eval_int(struct f_inst *expr)
+{
+ /* Called independently in parse-time to eval expressions */
+ struct f_val res = f_eval(expr, cfg_mem);
if (res.type != T_INT)
cf_error("Integer expression expected");
+
return res.val.i;
}
diff --git a/filter/filter.h b/filter/filter.h
index 2386fc95..07a4c9e4 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -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;
diff --git a/filter/test.conf b/filter/test.conf
index 64e6d91b..ae8a95a6 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -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);
diff --git a/filter/tree.c b/filter/tree.c
index f6ab75b4..ee9f448a 100644
--- a/filter/tree.c
+++ b/filter/tree.c
@@ -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, "]");
+}
diff --git a/filter/trie.c b/filter/trie.c
index 581332c6..217d72c3 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -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, "]");
}