Filter data manipulation functions separated to their file
This commit is contained in:
parent
87bd7cd7b0
commit
5289304519
7 changed files with 572 additions and 649 deletions
|
@ -1,4 +1,4 @@
|
||||||
src := filter.c f-util.c tree.c trie.c inst-gen.c
|
src := filter.c data.c f-util.c tree.c trie.c inst-gen.c
|
||||||
obj := $(src-o-files)
|
obj := $(src-o-files)
|
||||||
$(all-daemon)
|
$(all-daemon)
|
||||||
$(cf-local)
|
$(cf-local)
|
||||||
|
|
519
filter/data.c
Normal file
519
filter/data.c
Normal file
|
@ -0,0 +1,519 @@
|
||||||
|
/*
|
||||||
|
* Filters: utility functions
|
||||||
|
*
|
||||||
|
* (c) 1998 Pavel Machek <pavel@ucw.cz>
|
||||||
|
* (c) 2019 Maria Matejka <mq@jmq.cz>
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nest/bird.h"
|
||||||
|
#include "lib/lists.h"
|
||||||
|
#include "lib/resource.h"
|
||||||
|
#include "lib/socket.h"
|
||||||
|
#include "lib/string.h"
|
||||||
|
#include "lib/unaligned.h"
|
||||||
|
#include "lib/net.h"
|
||||||
|
#include "lib/ip.h"
|
||||||
|
#include "nest/route.h"
|
||||||
|
#include "nest/protocol.h"
|
||||||
|
#include "nest/iface.h"
|
||||||
|
#include "nest/attrs.h"
|
||||||
|
#include "conf/conf.h"
|
||||||
|
#include "filter/filter.h"
|
||||||
|
#include "filter/f-inst.h"
|
||||||
|
#include "filter/data.h"
|
||||||
|
|
||||||
|
const struct f_val f_const_empty_path = {
|
||||||
|
.type = T_PATH,
|
||||||
|
.val.ad = &null_adata,
|
||||||
|
}, f_const_empty_clist = {
|
||||||
|
.type = T_CLIST,
|
||||||
|
.val.ad = &null_adata,
|
||||||
|
}, f_const_empty_eclist = {
|
||||||
|
.type = T_ECLIST,
|
||||||
|
.val.ad = &null_adata,
|
||||||
|
}, f_const_empty_lclist = {
|
||||||
|
.type = T_LCLIST,
|
||||||
|
.val.ad = &null_adata,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct adata *
|
||||||
|
adata_empty(struct linpool *pool, int l)
|
||||||
|
{
|
||||||
|
struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
|
||||||
|
res->length = l;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pm_format(const struct f_path_mask *p, buffer *buf)
|
||||||
|
{
|
||||||
|
buffer_puts(buf, "[= ");
|
||||||
|
|
||||||
|
for (uint i=0; i<p->len; i++)
|
||||||
|
{
|
||||||
|
switch(p->item[i].kind)
|
||||||
|
{
|
||||||
|
case PM_ASN:
|
||||||
|
buffer_print(buf, "%u ", p->item[i].asn);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PM_QUESTION:
|
||||||
|
buffer_puts(buf, "? ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PM_ASTERISK:
|
||||||
|
buffer_puts(buf, "* ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PM_ASN_RANGE:
|
||||||
|
buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PM_ASN_EXPR:
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_puts(buf, "=]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
lcomm_cmp(lcomm v1, lcomm v2)
|
||||||
|
{
|
||||||
|
if (v1.asn != v2.asn)
|
||||||
|
return (v1.asn > v2.asn) ? 1 : -1;
|
||||||
|
if (v1.ldp1 != v2.ldp1)
|
||||||
|
return (v1.ldp1 > v2.ldp1) ? 1 : -1;
|
||||||
|
if (v1.ldp2 != v2.ldp2)
|
||||||
|
return (v1.ldp2 > v2.ldp2) ? 1 : -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* val_compare - compare two values
|
||||||
|
* @v1: first value
|
||||||
|
* @v2: second value
|
||||||
|
*
|
||||||
|
* Compares two values and returns -1, 0, 1 on <, =, > or F_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(const struct f_val *v1, const struct f_val *v2)
|
||||||
|
{
|
||||||
|
if (v1->type != v2->type) {
|
||||||
|
if (v1->type == T_VOID) /* Hack for else */
|
||||||
|
return -1;
|
||||||
|
if (v2->type == T_VOID)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* IP->Quad implicit conversion */
|
||||||
|
if ((v1->type == T_QUAD) && val_is_ip4(v2))
|
||||||
|
return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
|
||||||
|
if (val_is_ip4(v1) && (v2->type == T_QUAD))
|
||||||
|
return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
|
||||||
|
|
||||||
|
debug( "Types do not match in val_compare\n" );
|
||||||
|
return F_CMP_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (v1->type) {
|
||||||
|
case T_VOID:
|
||||||
|
return 0;
|
||||||
|
case T_ENUM:
|
||||||
|
case T_INT:
|
||||||
|
case T_BOOL:
|
||||||
|
case T_PAIR:
|
||||||
|
case T_QUAD:
|
||||||
|
return uint_cmp(v1->val.i, v2->val.i);
|
||||||
|
case T_EC:
|
||||||
|
case T_RD:
|
||||||
|
return u64_cmp(v1->val.ec, v2->val.ec);
|
||||||
|
case T_LC:
|
||||||
|
return lcomm_cmp(v1->val.lc, v2->val.lc);
|
||||||
|
case T_IP:
|
||||||
|
return ipa_compare(v1->val.ip, v2->val.ip);
|
||||||
|
case T_NET:
|
||||||
|
return net_compare(v1->val.net, v2->val.net);
|
||||||
|
case T_STRING:
|
||||||
|
return strcmp(v1->val.s, v2->val.s);
|
||||||
|
default:
|
||||||
|
return F_CMP_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
|
||||||
|
{
|
||||||
|
if (m1->len != m2->len)
|
||||||
|
|
||||||
|
for (uint i=0; i<m1->len; i++)
|
||||||
|
{
|
||||||
|
if (m1->item[i].kind != m2->item[i].kind)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (m1->item[i].kind) {
|
||||||
|
case PM_ASN:
|
||||||
|
if (m1->item[i].asn != m2->item[i].asn)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case PM_ASN_EXPR:
|
||||||
|
if (!f_same(m1->item[i].expr, m2->item[i].expr))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case PM_ASN_RANGE:
|
||||||
|
if (m1->item[i].from != m2->item[i].from)
|
||||||
|
return 0;
|
||||||
|
if (m1->item[i].to != m2->item[i].to)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(const struct f_val *v1, const struct f_val *v2)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = val_compare(v1, v2);
|
||||||
|
if (rc != F_CMP_ERROR)
|
||||||
|
return !rc;
|
||||||
|
|
||||||
|
if (v1->type != v2->type)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (v1->type) {
|
||||||
|
case T_PATH_MASK:
|
||||||
|
return pm_same(v1->val.path_mask, v2->val.path_mask);
|
||||||
|
case T_PATH:
|
||||||
|
case T_CLIST:
|
||||||
|
case T_ECLIST:
|
||||||
|
case T_LCLIST:
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clist_set_type(const struct f_tree *set, struct f_val *v)
|
||||||
|
{
|
||||||
|
switch (set->from.type)
|
||||||
|
{
|
||||||
|
case T_PAIR:
|
||||||
|
v->type = T_PAIR;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case T_QUAD:
|
||||||
|
v->type = T_QUAD;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case T_IP:
|
||||||
|
if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
|
||||||
|
{
|
||||||
|
v->type = T_QUAD;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* Fall through */
|
||||||
|
default:
|
||||||
|
v->type = T_VOID;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
clist_match_set(const struct adata *clist, const struct f_tree *set)
|
||||||
|
{
|
||||||
|
if (!clist)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct f_val v;
|
||||||
|
if (!clist_set_type(set, &v))
|
||||||
|
return F_CMP_ERROR;
|
||||||
|
|
||||||
|
u32 *l = (u32 *) clist->data;
|
||||||
|
u32 *end = l + clist->length/4;
|
||||||
|
|
||||||
|
while (l < end) {
|
||||||
|
v.val.i = *l++;
|
||||||
|
if (find_tree(set, &v))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
eclist_match_set(const struct adata *list, const struct f_tree *set)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!eclist_set_type(set))
|
||||||
|
return F_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 int
|
||||||
|
lclist_match_set(const struct adata *list, const struct f_tree *set)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!lclist_set_type(set))
|
||||||
|
return F_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_LC;
|
||||||
|
for (i = 0; i < len; i += 3) {
|
||||||
|
v.val.lc = lc_get(l, i);
|
||||||
|
if (find_tree(set, &v))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct adata *
|
||||||
|
clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
|
||||||
|
struct f_val v;
|
||||||
|
if (tree)
|
||||||
|
clist_set_type(set->val.t, &v);
|
||||||
|
else
|
||||||
|
v.type = T_PAIR;
|
||||||
|
|
||||||
|
int len = int_set_get_size(list);
|
||||||
|
u32 *l = int_set_get_data(list);
|
||||||
|
u32 tmp[len];
|
||||||
|
u32 *k = tmp;
|
||||||
|
u32 *end = l + len;
|
||||||
|
|
||||||
|
while (l < end) {
|
||||||
|
v.val.i = *l++;
|
||||||
|
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
|
||||||
|
if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
|
||||||
|
*k++ = v.val.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint nl = (k - tmp) * sizeof(u32);
|
||||||
|
if (nl == list->length)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
struct adata *res = adata_empty(pool, nl);
|
||||||
|
memcpy(res->data, tmp, nl);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct adata *
|
||||||
|
eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
|
||||||
|
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);
|
||||||
|
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
|
||||||
|
if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
|
||||||
|
*k++ = l[i];
|
||||||
|
*k++ = l[i+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint nl = (k - tmp) * sizeof(u32);
|
||||||
|
if (nl == list->length)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
struct adata *res = adata_empty(pool, nl);
|
||||||
|
memcpy(res->data, tmp, nl);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct adata *
|
||||||
|
lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
|
||||||
|
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_LC;
|
||||||
|
for (i = 0; i < len; i += 3) {
|
||||||
|
v.val.lc = lc_get(l, i);
|
||||||
|
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
|
||||||
|
if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
|
||||||
|
k = lc_copy(k, l+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint nl = (k - tmp) * sizeof(u32);
|
||||||
|
if (nl == list->length)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
struct adata *res = adata_empty(pool, nl);
|
||||||
|
memcpy(res->data, tmp, nl);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* val_in_range - implement |~| operator
|
||||||
|
* @v1: element
|
||||||
|
* @v2: set
|
||||||
|
*
|
||||||
|
* Checks if @v1 is element (|~| operator) of @v2.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
val_in_range(const struct f_val *v1, const 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_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);
|
||||||
|
/* IP->Quad implicit conversion */
|
||||||
|
if (val_is_ip4(v1) && (v2->type == T_CLIST))
|
||||||
|
return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
|
||||||
|
|
||||||
|
if ((v1->type == T_EC) && (v2->type == T_ECLIST))
|
||||||
|
return ec_set_contains(v2->val.ad, v1->val.ec);
|
||||||
|
|
||||||
|
if ((v1->type == T_LC) && (v2->type == T_LCLIST))
|
||||||
|
return lc_set_contains(v2->val.ad, v1->val.lc);
|
||||||
|
|
||||||
|
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_NET))
|
||||||
|
return ipa_in_netX(v1->val.ip, v2->val.net);
|
||||||
|
|
||||||
|
if ((v1->type == T_NET) && (v2->type == T_NET))
|
||||||
|
return net_in_netX(v1->val.net, v2->val.net);
|
||||||
|
|
||||||
|
if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
|
||||||
|
return trie_match_net(v2->val.ti, v1->val.net);
|
||||||
|
|
||||||
|
if (v2->type != T_SET)
|
||||||
|
return F_CMP_ERROR;
|
||||||
|
|
||||||
|
/* With integrated Quad<->IP implicit conversion */
|
||||||
|
if ((v1->type == v2->val.t->from.type) ||
|
||||||
|
((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
|
||||||
|
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)
|
||||||
|
return eclist_match_set(v1->val.ad, v2->val.t);
|
||||||
|
|
||||||
|
if (v1->type == T_LCLIST)
|
||||||
|
return lclist_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 F_CMP_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* val_format - format filter value
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
val_format(const struct f_val *v, buffer *buf)
|
||||||
|
{
|
||||||
|
char buf2[1024];
|
||||||
|
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, "%u", v->val.i); return;
|
||||||
|
case T_STRING: buffer_print(buf, "%s", v->val.s); return;
|
||||||
|
case T_IP: buffer_print(buf, "%I", v->val.ip); return;
|
||||||
|
case T_NET: buffer_print(buf, "%N", v->val.net); return;
|
||||||
|
case T_PAIR: buffer_print(buf, "(%u,%u)", 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_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
|
||||||
|
case T_RD: rd_format(v->val.ec, buf2, 1024); 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)%u", 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_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char val_dump_buffer[1024];
|
||||||
|
const char *
|
||||||
|
val_dump(const struct f_val *v) {
|
||||||
|
static buffer b = {
|
||||||
|
.start = val_dump_buffer,
|
||||||
|
.end = val_dump_buffer + 1024,
|
||||||
|
};
|
||||||
|
b.pos = b.start;
|
||||||
|
val_format(v, &b);
|
||||||
|
return val_dump_buffer;
|
||||||
|
}
|
||||||
|
|
|
@ -164,6 +164,39 @@ int trie_match_net(const struct f_trie *t, const net_addr *n);
|
||||||
int trie_same(const struct f_trie *t1, const struct f_trie *t2);
|
int trie_same(const struct f_trie *t1, const struct f_trie *t2);
|
||||||
void trie_format(const struct f_trie *t, buffer *buf);
|
void trie_format(const struct f_trie *t, buffer *buf);
|
||||||
|
|
||||||
|
#define F_CMP_ERROR 999
|
||||||
|
|
||||||
|
int val_same(const struct f_val *v1, const struct f_val *v2);
|
||||||
|
int val_compare(const struct f_val *v1, const struct f_val *v2);
|
||||||
|
void val_format(const struct f_val *v, buffer *buf);
|
||||||
|
const char *val_dump(const struct f_val *v);
|
||||||
|
|
||||||
|
static inline int val_is_ip4(const struct f_val *v)
|
||||||
|
{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); }
|
||||||
|
int val_in_range(const struct f_val *v1, const struct f_val *v2);
|
||||||
|
|
||||||
|
int clist_set_type(const struct f_tree *set, struct f_val *v);
|
||||||
|
static inline int eclist_set_type(const struct f_tree *set)
|
||||||
|
{ return set->from.type == T_EC; }
|
||||||
|
static inline int lclist_set_type(const struct f_tree *set)
|
||||||
|
{ return set->from.type == T_LC; }
|
||||||
|
|
||||||
|
const struct adata *clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos);
|
||||||
|
const struct adata *eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos);
|
||||||
|
const struct adata *lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos);
|
||||||
|
|
||||||
|
|
||||||
|
/* Special undef value for paths and clists */
|
||||||
|
static inline int
|
||||||
|
undef_value(struct f_val v)
|
||||||
|
{
|
||||||
|
return ((v.type == T_PATH) || (v.type == T_CLIST) ||
|
||||||
|
(v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
|
||||||
|
(v.val.ad == &null_adata);
|
||||||
|
}
|
||||||
|
|
||||||
extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist;
|
extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist;
|
||||||
|
|
||||||
|
enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -165,7 +165,7 @@
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
ARG_ANY(2);
|
ARG_ANY(2);
|
||||||
int i = val_compare(&v1, &v2);
|
int i = val_compare(&v1, &v2);
|
||||||
if (i == CMP_ERROR)
|
if (i == F_CMP_ERROR)
|
||||||
runtime( "Can't compare values of incompatible types" );
|
runtime( "Can't compare values of incompatible types" );
|
||||||
RESULT(T_BOOL, i, (i == -1));
|
RESULT(T_BOOL, i, (i == -1));
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
ARG_ANY(2);
|
ARG_ANY(2);
|
||||||
int i = val_compare(&v1, &v2);
|
int i = val_compare(&v1, &v2);
|
||||||
if (i == CMP_ERROR)
|
if (i == F_CMP_ERROR)
|
||||||
runtime( "Can't compare values of incompatible types" );
|
runtime( "Can't compare values of incompatible types" );
|
||||||
RESULT(T_BOOL, i, (i != 1));
|
RESULT(T_BOOL, i, (i != 1));
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
ARG_ANY(2);
|
ARG_ANY(2);
|
||||||
int i = val_in_range(&v1, &v2);
|
int i = val_in_range(&v1, &v2);
|
||||||
if (i == CMP_ERROR)
|
if (i == F_CMP_ERROR)
|
||||||
runtime( "~ applied on unknown type pair" );
|
runtime( "~ applied on unknown type pair" );
|
||||||
RESULT(T_BOOL, i, !!i);
|
RESULT(T_BOOL, i, !!i);
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
ARG_ANY(2);
|
ARG_ANY(2);
|
||||||
int i = val_in_range(&v1, &v2);
|
int i = val_in_range(&v1, &v2);
|
||||||
if (res.val.i == CMP_ERROR)
|
if (res.val.i == F_CMP_ERROR)
|
||||||
runtime( "!~ applied on unknown type pair" );
|
runtime( "!~ applied on unknown type pair" );
|
||||||
RESULT(T_BOOL, i, !i);
|
RESULT(T_BOOL, i, !i);
|
||||||
}
|
}
|
||||||
|
|
642
filter/filter.c
642
filter/filter.c
|
@ -50,8 +50,6 @@
|
||||||
#include "filter/f-inst.h"
|
#include "filter/f-inst.h"
|
||||||
#include "filter/data.h"
|
#include "filter/data.h"
|
||||||
|
|
||||||
#define CMP_ERROR 999
|
|
||||||
|
|
||||||
/* Internal filter state, to be allocated on stack when executing filters */
|
/* Internal filter state, to be allocated on stack when executing filters */
|
||||||
struct filter_state {
|
struct filter_state {
|
||||||
struct rte **rte;
|
struct rte **rte;
|
||||||
|
@ -133,507 +131,6 @@ f_instruction_name(enum f_instruction_code fi)
|
||||||
bug("Got unknown instruction code: %d", fi);
|
bug("Got unknown instruction code: %d", fi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Special undef value for paths and clists */
|
|
||||||
static inline int
|
|
||||||
undef_value(struct f_val v)
|
|
||||||
{
|
|
||||||
return ((v.type == T_PATH) || (v.type == T_CLIST) ||
|
|
||||||
(v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
|
|
||||||
(v.val.ad == &null_adata);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct f_val f_const_empty_path = {
|
|
||||||
.type = T_PATH,
|
|
||||||
.val.ad = &null_adata,
|
|
||||||
}, f_const_empty_clist = {
|
|
||||||
.type = T_CLIST,
|
|
||||||
.val.ad = &null_adata,
|
|
||||||
}, f_const_empty_eclist = {
|
|
||||||
.type = T_ECLIST,
|
|
||||||
.val.ad = &null_adata,
|
|
||||||
}, f_const_empty_lclist = {
|
|
||||||
.type = T_LCLIST,
|
|
||||||
.val.ad = &null_adata,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct adata *
|
|
||||||
adata_empty(struct linpool *pool, int l)
|
|
||||||
{
|
|
||||||
struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
|
|
||||||
res->length = l;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pm_format(const struct f_path_mask *p, buffer *buf)
|
|
||||||
{
|
|
||||||
buffer_puts(buf, "[= ");
|
|
||||||
|
|
||||||
for (uint i=0; i<p->len; i++)
|
|
||||||
{
|
|
||||||
switch(p->item[i].kind)
|
|
||||||
{
|
|
||||||
case PM_ASN:
|
|
||||||
buffer_print(buf, "%u ", p->item[i].asn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PM_QUESTION:
|
|
||||||
buffer_puts(buf, "? ");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PM_ASTERISK:
|
|
||||||
buffer_puts(buf, "* ");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PM_ASN_RANGE:
|
|
||||||
buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PM_ASN_EXPR:
|
|
||||||
ASSERT(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_puts(buf, "=]");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int val_is_ip4(const struct f_val *v)
|
|
||||||
{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); }
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
lcomm_cmp(lcomm v1, lcomm v2)
|
|
||||||
{
|
|
||||||
if (v1.asn != v2.asn)
|
|
||||||
return (v1.asn > v2.asn) ? 1 : -1;
|
|
||||||
if (v1.ldp1 != v2.ldp1)
|
|
||||||
return (v1.ldp1 > v2.ldp1) ? 1 : -1;
|
|
||||||
if (v1.ldp2 != v2.ldp2)
|
|
||||||
return (v1.ldp2 > v2.ldp2) ? 1 : -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* val_compare - compare two values
|
|
||||||
* @v1: first value
|
|
||||||
* @v2: second value
|
|
||||||
*
|
|
||||||
* 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(const struct f_val *v1, const struct f_val *v2)
|
|
||||||
{
|
|
||||||
if (v1->type != v2->type) {
|
|
||||||
if (v1->type == T_VOID) /* Hack for else */
|
|
||||||
return -1;
|
|
||||||
if (v2->type == T_VOID)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* IP->Quad implicit conversion */
|
|
||||||
if ((v1->type == T_QUAD) && val_is_ip4(v2))
|
|
||||||
return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
|
|
||||||
if (val_is_ip4(v1) && (v2->type == T_QUAD))
|
|
||||||
return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
|
|
||||||
|
|
||||||
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:
|
|
||||||
case T_PAIR:
|
|
||||||
case T_QUAD:
|
|
||||||
return uint_cmp(v1->val.i, v2->val.i);
|
|
||||||
case T_EC:
|
|
||||||
case T_RD:
|
|
||||||
return u64_cmp(v1->val.ec, v2->val.ec);
|
|
||||||
case T_LC:
|
|
||||||
return lcomm_cmp(v1->val.lc, v2->val.lc);
|
|
||||||
case T_IP:
|
|
||||||
return ipa_compare(v1->val.ip, v2->val.ip);
|
|
||||||
case T_NET:
|
|
||||||
return net_compare(v1->val.net, v2->val.net);
|
|
||||||
case T_STRING:
|
|
||||||
return strcmp(v1->val.s, v2->val.s);
|
|
||||||
default:
|
|
||||||
return CMP_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
|
|
||||||
{
|
|
||||||
if (m1->len != m2->len)
|
|
||||||
|
|
||||||
for (uint i=0; i<m1->len; i++)
|
|
||||||
{
|
|
||||||
if (m1->item[i].kind != m2->item[i].kind)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (m1->item[i].kind) {
|
|
||||||
case PM_ASN:
|
|
||||||
if (m1->item[i].asn != m2->item[i].asn)
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case PM_ASN_EXPR:
|
|
||||||
if (!f_same(m1->item[i].expr, m2->item[i].expr))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case PM_ASN_RANGE:
|
|
||||||
if (m1->item[i].from != m2->item[i].from)
|
|
||||||
return 0;
|
|
||||||
if (m1->item[i].to != m2->item[i].to)
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(const struct f_val *v1, const 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_same(v1->val.path_mask, v2->val.path_mask);
|
|
||||||
case T_PATH:
|
|
||||||
case T_CLIST:
|
|
||||||
case T_ECLIST:
|
|
||||||
case T_LCLIST:
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
clist_set_type(const struct f_tree *set, struct f_val *v)
|
|
||||||
{
|
|
||||||
switch (set->from.type)
|
|
||||||
{
|
|
||||||
case T_PAIR:
|
|
||||||
v->type = T_PAIR;
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case T_QUAD:
|
|
||||||
v->type = T_QUAD;
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case T_IP:
|
|
||||||
if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
|
|
||||||
{
|
|
||||||
v->type = T_QUAD;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* Fall through */
|
|
||||||
default:
|
|
||||||
v->type = T_VOID;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
eclist_set_type(const struct f_tree *set)
|
|
||||||
{ return set->from.type == T_EC; }
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
lclist_set_type(const struct f_tree *set)
|
|
||||||
{ return set->from.type == T_LC; }
|
|
||||||
|
|
||||||
static int
|
|
||||||
clist_match_set(const struct adata *clist, const struct f_tree *set)
|
|
||||||
{
|
|
||||||
if (!clist)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
struct f_val v;
|
|
||||||
if (!clist_set_type(set, &v))
|
|
||||||
return CMP_ERROR;
|
|
||||||
|
|
||||||
u32 *l = (u32 *) clist->data;
|
|
||||||
u32 *end = l + clist->length/4;
|
|
||||||
|
|
||||||
while (l < end) {
|
|
||||||
v.val.i = *l++;
|
|
||||||
if (find_tree(set, &v))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
eclist_match_set(const struct adata *list, const 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 int
|
|
||||||
lclist_match_set(const struct adata *list, const struct f_tree *set)
|
|
||||||
{
|
|
||||||
if (!list)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!lclist_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_LC;
|
|
||||||
for (i = 0; i < len; i += 3) {
|
|
||||||
v.val.lc = lc_get(l, i);
|
|
||||||
if (find_tree(set, &v))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct adata *
|
|
||||||
clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
|
|
||||||
{
|
|
||||||
if (!list)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
|
|
||||||
struct f_val v;
|
|
||||||
if (tree)
|
|
||||||
clist_set_type(set->val.t, &v);
|
|
||||||
else
|
|
||||||
v.type = T_PAIR;
|
|
||||||
|
|
||||||
int len = int_set_get_size(list);
|
|
||||||
u32 *l = int_set_get_data(list);
|
|
||||||
u32 tmp[len];
|
|
||||||
u32 *k = tmp;
|
|
||||||
u32 *end = l + len;
|
|
||||||
|
|
||||||
while (l < end) {
|
|
||||||
v.val.i = *l++;
|
|
||||||
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
|
|
||||||
if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
|
|
||||||
*k++ = v.val.i;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint nl = (k - tmp) * sizeof(u32);
|
|
||||||
if (nl == list->length)
|
|
||||||
return list;
|
|
||||||
|
|
||||||
struct adata *res = adata_empty(pool, nl);
|
|
||||||
memcpy(res->data, tmp, nl);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct adata *
|
|
||||||
eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
|
|
||||||
{
|
|
||||||
if (!list)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
|
|
||||||
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);
|
|
||||||
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
|
|
||||||
if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
|
|
||||||
*k++ = l[i];
|
|
||||||
*k++ = l[i+1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint nl = (k - tmp) * sizeof(u32);
|
|
||||||
if (nl == list->length)
|
|
||||||
return list;
|
|
||||||
|
|
||||||
struct adata *res = adata_empty(pool, nl);
|
|
||||||
memcpy(res->data, tmp, nl);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct adata *
|
|
||||||
lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
|
|
||||||
{
|
|
||||||
if (!list)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
|
|
||||||
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_LC;
|
|
||||||
for (i = 0; i < len; i += 3) {
|
|
||||||
v.val.lc = lc_get(l, i);
|
|
||||||
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
|
|
||||||
if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
|
|
||||||
k = lc_copy(k, l+i);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint nl = (k - tmp) * sizeof(u32);
|
|
||||||
if (nl == list->length)
|
|
||||||
return list;
|
|
||||||
|
|
||||||
struct adata *res = adata_empty(pool, nl);
|
|
||||||
memcpy(res->data, tmp, nl);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* val_in_range - implement |~| operator
|
|
||||||
* @v1: element
|
|
||||||
* @v2: set
|
|
||||||
*
|
|
||||||
* Checks if @v1 is element (|~| operator) of @v2.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
val_in_range(const struct f_val *v1, const 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_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);
|
|
||||||
/* IP->Quad implicit conversion */
|
|
||||||
if (val_is_ip4(v1) && (v2->type == T_CLIST))
|
|
||||||
return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
|
|
||||||
|
|
||||||
if ((v1->type == T_EC) && (v2->type == T_ECLIST))
|
|
||||||
return ec_set_contains(v2->val.ad, v1->val.ec);
|
|
||||||
|
|
||||||
if ((v1->type == T_LC) && (v2->type == T_LCLIST))
|
|
||||||
return lc_set_contains(v2->val.ad, v1->val.lc);
|
|
||||||
|
|
||||||
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_NET))
|
|
||||||
return ipa_in_netX(v1->val.ip, v2->val.net);
|
|
||||||
|
|
||||||
if ((v1->type == T_NET) && (v2->type == T_NET))
|
|
||||||
return net_in_netX(v1->val.net, v2->val.net);
|
|
||||||
|
|
||||||
if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
|
|
||||||
return trie_match_net(v2->val.ti, v1->val.net);
|
|
||||||
|
|
||||||
if (v2->type != T_SET)
|
|
||||||
return CMP_ERROR;
|
|
||||||
|
|
||||||
/* With integrated Quad<->IP implicit conversion */
|
|
||||||
if ((v1->type == v2->val.t->from.type) ||
|
|
||||||
((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
|
|
||||||
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)
|
|
||||||
return eclist_match_set(v1->val.ad, v2->val.t);
|
|
||||||
|
|
||||||
if (v1->type == T_LCLIST)
|
|
||||||
return lclist_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_format - format filter value
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
val_format(const struct f_val *v, buffer *buf)
|
|
||||||
{
|
|
||||||
char buf2[1024];
|
|
||||||
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, "%u", v->val.i); return;
|
|
||||||
case T_STRING: buffer_print(buf, "%s", v->val.s); return;
|
|
||||||
case T_IP: buffer_print(buf, "%I", v->val.ip); return;
|
|
||||||
case T_NET: buffer_print(buf, "%N", v->val.net); return;
|
|
||||||
case T_PAIR: buffer_print(buf, "(%u,%u)", 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_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
|
|
||||||
case T_RD: rd_format(v->val.ec, buf2, 1024); 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)%u", 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_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void f_cache_eattrs(struct filter_state *fs)
|
static inline void f_cache_eattrs(struct filter_state *fs)
|
||||||
{
|
{
|
||||||
fs->eattrs = &((*fs->rte)->attrs->eattrs);
|
fs->eattrs = &((*fs->rte)->attrs->eattrs);
|
||||||
|
@ -687,19 +184,6 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
||||||
#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1)
|
#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1)
|
||||||
static const char f_dump_line_indent_str[] = " ";
|
static const char f_dump_line_indent_str[] = " ";
|
||||||
|
|
||||||
static char val_dump_buffer[1024];
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
val_dump(const struct f_val *v) {
|
|
||||||
static buffer b = {
|
|
||||||
.start = val_dump_buffer,
|
|
||||||
.end = val_dump_buffer + 1024,
|
|
||||||
};
|
|
||||||
b.pos = b.start;
|
|
||||||
val_format(v, &b);
|
|
||||||
return val_dump_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void f_dump_line(const struct f_line *dest, int indent);
|
static void f_dump_line(const struct f_line *dest, int indent);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -891,122 +375,6 @@ f_same(const struct f_line *fl1, const struct f_line *fl2)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
case FI_ADD: /* fall through */
|
|
||||||
case FI_SUBTRACT:
|
|
||||||
case FI_MULTIPLY:
|
|
||||||
case FI_DIVIDE:
|
|
||||||
case FI_OR:
|
|
||||||
case FI_AND:
|
|
||||||
case FI_PAIR_CONSTRUCT:
|
|
||||||
case FI_EC_CONSTRUCT:
|
|
||||||
case FI_NEQ:
|
|
||||||
case FI_EQ:
|
|
||||||
case FI_LT:
|
|
||||||
case FI_LTE: TWOARGS; break;
|
|
||||||
|
|
||||||
case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a[0].p, f2->a[0].p)) return 0; break;
|
|
||||||
|
|
||||||
case FI_NOT: ONEARG; break;
|
|
||||||
case FI_NOT_MATCH:
|
|
||||||
case FI_MATCH: TWOARGS; break;
|
|
||||||
case FI_DEFINED: ONEARG; break;
|
|
||||||
case FI_TYPE: ONEARG; break;
|
|
||||||
|
|
||||||
case FI_LC_CONSTRUCT:
|
|
||||||
THREEARGS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FI_SET:
|
|
||||||
ARG(2);
|
|
||||||
{
|
|
||||||
struct symbol *s1, *s2;
|
|
||||||
s1 = f1->a[0].p;
|
|
||||||
s2 = f2->a[0].p;
|
|
||||||
if (strcmp(s1->name, s2->name))
|
|
||||||
return 0;
|
|
||||||
if (s1->class != s2->class)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FI_CONSTANT:
|
|
||||||
switch (f1->aux) {
|
|
||||||
|
|
||||||
case T_PREFIX_SET:
|
|
||||||
if (!trie_same(f1->a[1].p, f2->a[1].p))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_SET:
|
|
||||||
if (!same_tree(f1->a[1].p, f2->a[1].p))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_STRING:
|
|
||||||
if (strcmp(f1->a[1].p, f2->a[1].p))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
A2_SAME;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FI_CONSTANT_INDIRECT:
|
|
||||||
if (!val_same(* (struct f_val *) f1->a[0].p, * (struct f_val *) f2->a[0].p))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FI_VARIABLE:
|
|
||||||
if (strcmp((char *) f1->a[1].p, (char *) f2->a[1].p))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case FI_PRINT: case FI_LENGTH: ONEARG; break;
|
|
||||||
case FI_CONDITION: THREEARGS; break;
|
|
||||||
case FI_NOP: case FI_EMPTY: break;
|
|
||||||
case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
|
|
||||||
case FI_PREF_GET:
|
|
||||||
case FI_RTA_GET: A2_SAME; break;
|
|
||||||
case FI_EA_GET: A2_SAME; break;
|
|
||||||
case FI_PREF_SET:
|
|
||||||
case FI_RTA_SET:
|
|
||||||
case FI_EA_SET: ONEARG; A2_SAME; break;
|
|
||||||
|
|
||||||
case FI_RETURN: ONEARG; break;
|
|
||||||
case FI_ROA_MAXLEN: ONEARG; break;
|
|
||||||
case FI_ROA_ASN: ONEARG; break;
|
|
||||||
case FI_SADR_SRC: ONEARG; break;
|
|
||||||
case FI_IP: ONEARG; break;
|
|
||||||
case FI_IS_V4: ONEARG; break;
|
|
||||||
case FI_ROUTE_DISTINGUISHER: ONEARG; break;
|
|
||||||
case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
|
|
||||||
ONEARG;
|
|
||||||
if (!i_same(f1->a[1].p, f2->a[1].p))
|
|
||||||
return 0;
|
|
||||||
f2->a[1].p = f1->a[1].p;
|
|
||||||
break;
|
|
||||||
case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
|
|
||||||
case FI_SWITCH: ONEARG; if (!same_tree(f1->a[1].p, f2->a[1].p)) return 0; break;
|
|
||||||
case FI_IP_MASK: TWOARGS; break;
|
|
||||||
case FI_PATH_PREPEND: TWOARGS; break;
|
|
||||||
case FI_CLIST_ADD_DEL: TWOARGS; break;
|
|
||||||
case FI_AS_PATH_FIRST:
|
|
||||||
case FI_AS_PATH_LAST:
|
|
||||||
case FI_AS_PATH_LAST_NAG: ONEARG; break;
|
|
||||||
case FI_ROA_CHECK:
|
|
||||||
TWOARGS;
|
|
||||||
/* FIXME: ROA check results may change anyway */
|
|
||||||
if (strcmp(f1->a[2].rtc->name,
|
|
||||||
f2->a[2].rtc->name))
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case FI_FORMAT: ONEARG; break;
|
|
||||||
case FI_ASSERT: ONEARG; break;
|
|
||||||
default:
|
|
||||||
bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* f_run - run a filter for a route
|
* f_run - run a filter for a route
|
||||||
* @filter: filter to run
|
* @filter: filter to run
|
||||||
|
@ -1133,6 +501,16 @@ f_eval_int(const struct f_line *expr)
|
||||||
return val.val.i;
|
return val.val.i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum filter_return
|
||||||
|
f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf)
|
||||||
|
{
|
||||||
|
struct f_val val;
|
||||||
|
enum filter_return fret = f_eval(expr, tmp_pool, &val);
|
||||||
|
if (fret > F_RETURN)
|
||||||
|
val_format(&val, buf);
|
||||||
|
return fret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* filter_same - compare two filters
|
* filter_same - compare two filters
|
||||||
* @new: first filter to be compared
|
* @new: first filter to be compared
|
||||||
|
|
|
@ -40,17 +40,13 @@ struct rte;
|
||||||
|
|
||||||
enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
|
enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
|
||||||
enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
|
enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
|
||||||
enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres);
|
|
||||||
uint f_eval_int(const struct f_line *expr);
|
uint f_eval_int(const struct f_line *expr);
|
||||||
|
enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);
|
||||||
|
|
||||||
char *filter_name(struct filter *filter);
|
char *filter_name(struct filter *filter);
|
||||||
int filter_same(struct filter *new, struct filter *old);
|
int filter_same(struct filter *new, struct filter *old);
|
||||||
int f_same(const struct f_line *f1, const struct f_line *f2);
|
int f_same(const struct f_line *f1, const struct f_line *f2);
|
||||||
|
|
||||||
int val_compare(const struct f_val *v1, const struct f_val *v2);
|
|
||||||
|
|
||||||
void val_format(const struct f_val *v, buffer *buf);
|
|
||||||
|
|
||||||
#define FILTER_ACCEPT NULL
|
#define FILTER_ACCEPT NULL
|
||||||
#define FILTER_REJECT ((void *) 1)
|
#define FILTER_REJECT ((void *) 1)
|
||||||
#define FILTER_UNDEF ((void *) 2) /* Used in BGP */
|
#define FILTER_UNDEF ((void *) 2) /* Used in BGP */
|
||||||
|
|
11
nest/cmds.c
11
nest/cmds.c
|
@ -15,7 +15,6 @@
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "filter/filter.h"
|
#include "filter/filter.h"
|
||||||
#include "filter/data.h"
|
|
||||||
|
|
||||||
extern int shutting_down;
|
extern int shutting_down;
|
||||||
extern int configuring;
|
extern int configuring;
|
||||||
|
@ -98,16 +97,14 @@ cmd_show_memory(void)
|
||||||
void
|
void
|
||||||
cmd_eval(const struct f_line *expr)
|
cmd_eval(const struct f_line *expr)
|
||||||
{
|
{
|
||||||
/* TODO: Return directly the string from eval */
|
buffer buf;
|
||||||
struct f_val v;
|
LOG_BUFFER_INIT(buf);
|
||||||
if (f_eval(expr, this_cli->parser_pool, &v) > F_RETURN)
|
|
||||||
|
if (f_eval_buf(expr, this_cli->parser_pool, &buf) > F_RETURN)
|
||||||
{
|
{
|
||||||
cli_msg(8008, "runtime error");
|
cli_msg(8008, "runtime error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer buf;
|
|
||||||
LOG_BUFFER_INIT(buf);
|
|
||||||
val_format(&v, &buf);
|
|
||||||
cli_msg(23, "%s", buf.start);
|
cli_msg(23, "%s", buf.start);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue