summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
Diffstat (limited to 'filter')
-rw-r--r--filter/filter.c82
1 files changed, 57 insertions, 25 deletions
diff --git a/filter/filter.c b/filter/filter.c
index a4f12330..3b14fc0c 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -462,7 +462,7 @@ static int f_flags;
static inline void f_rte_cow(void)
{
- *f_rte = rte_cow(*f_rte);
+ *f_rte = rte_cow(*f_rte);
}
/*
@@ -479,7 +479,7 @@ f_rta_cow(void)
/* Store old rta to free it later */
f_old_rta = (*f_rte)->attrs;
- /*
+ /*
* Alloc new rta, do shallow copy and update rte. Fields eattrs
* and nexthops of rta are shared with f_old_rta (they will be
* copied when the cached rta will be obtained at the end of
@@ -516,6 +516,9 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
#define ACCESS_RTE \
do { if (!f_rte) runtime("No route to access"); } while (0)
+#define BITFIELD_MASK(what) \
+ (1u << (what->a2.i >> 24))
+
/**
* interpret
* @what: filter to interpret
@@ -526,7 +529,7 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
* Each instruction has 4 fields: code (which is instruction code),
* aux (which is extension to instruction code, typically type),
* arg1 and arg2 - arguments. Depending on instruction, arguments
- * are either integers, or pointers to instruction trees. Common
+ * are either integers, or pointers to instruction trees. Common
* instructions like +, that have two expressions as arguments use
* TWOARGS macro to get both of them evaluated.
*
@@ -585,7 +588,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" );
}
break;
-
+
case '&':
case '|':
ARG(v1, a1.p);
@@ -625,7 +628,7 @@ interpret(struct f_inst *what)
if (v1.type == T_INT) {
ipv4_used = 0; key = v1.val.i;
- }
+ }
else if (v1.type == T_QUAD) {
ipv4_used = 1; key = v1.val.i;
}
@@ -724,7 +727,7 @@ interpret(struct f_inst *what)
#endif
runtime( "Assigning to variable of incompatible type" );
}
- *vp = v2;
+ *vp = v2;
break;
/* some constants have value in a2, some in *a1.p, strange. */
@@ -864,12 +867,14 @@ interpret(struct f_inst *what)
ACCESS_RTE;
{
eattr *e = NULL;
+ u16 code = what->a2.i;
+
if (!(f_flags & FF_FORCE_TMPATTR))
- e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
- if (!e)
- e = ea_find( (*f_tmp_attrs), what->a2.i );
+ e = ea_find((*f_rte)->attrs->eattrs, code);
+ if (!e)
+ e = ea_find((*f_tmp_attrs), code);
if ((!e) && (f_flags & FF_FORCE_TMPATTR))
- e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
+ e = ea_find((*f_rte)->attrs->eattrs, code);
if (!e) {
/* A special case: undefined int_set looks like empty int_set */
@@ -878,8 +883,9 @@ interpret(struct f_inst *what)
res.val.ad = adata_empty(f_pool, 0);
break;
}
+
/* The same special case for ec_set */
- else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
+ if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
res.type = T_ECLIST;
res.val.ad = adata_empty(f_pool, 0);
break;
@@ -912,6 +918,10 @@ interpret(struct f_inst *what)
res.type = T_PATH;
res.val.ad = e->u.ptr;
break;
+ case EAF_TYPE_BITFIELD:
+ res.type = T_BOOL;
+ res.val.i = !!(e->u.data & BITFIELD_MASK(what));
+ break;
case EAF_TYPE_INT_SET:
res.type = T_CLIST;
res.val.ad = e->u.ptr;
@@ -933,13 +943,15 @@ interpret(struct f_inst *what)
ONEARG;
{
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
+ u16 code = what->a2.i;
l->next = NULL;
l->flags = EALF_SORTED;
l->count = 1;
- l->attrs[0].id = what->a2.i;
+ l->attrs[0].id = code;
l->attrs[0].flags = 0;
l->attrs[0].type = what->aux | EAF_ORIGINATED;
+
switch (what->aux & EAF_TYPE_MASK) {
case EAF_TYPE_INT:
if (v1.type != T_INT)
@@ -978,6 +990,26 @@ interpret(struct f_inst *what)
runtime( "Setting path attribute to non-path value" );
l->attrs[0].u.ptr = v1.val.ad;
break;
+ case EAF_TYPE_BITFIELD:
+ if (v1.type != T_BOOL)
+ runtime( "Setting bit in bitfield attribute to non-bool value" );
+ {
+ /* First, we have to find the old value */
+ eattr *e = NULL;
+ if (!(f_flags & FF_FORCE_TMPATTR))
+ e = ea_find((*f_rte)->attrs->eattrs, code);
+ if (!e)
+ e = ea_find((*f_tmp_attrs), code);
+ if ((!e) && (f_flags & FF_FORCE_TMPATTR))
+ e = ea_find((*f_rte)->attrs->eattrs, code);
+ u32 data = e ? e->u.data : 0;
+
+ if (v1.val.i)
+ l->attrs[0].u.data = data | BITFIELD_MASK(what);
+ else
+ l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
+ }
+ break;
case EAF_TYPE_INT_SET:
if (v1.type != T_CLIST)
runtime( "Setting clist attribute to non-clist value" );
@@ -1073,7 +1105,7 @@ interpret(struct f_inst *what)
res = interpret(what->a2.p);
if (res.type == T_RETURN)
return res;
- res.type &= ~T_RETURN;
+ res.type &= ~T_RETURN;
break;
case P('c','v'): /* Clear local variables */
for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
@@ -1090,7 +1122,7 @@ interpret(struct f_inst *what)
debug( "No else statement?\n");
break;
}
- }
+ }
/* It is actually possible to have t->data NULL */
res = interpret(t->data);
@@ -1184,10 +1216,10 @@ interpret(struct f_inst *what)
runtime("Can't add set");
else if (!arg_set)
res.val.ad = int_set_add(f_pool, v1.val.ad, n);
- else
+ else
res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
break;
-
+
case 'd':
if (!arg_set)
res.val.ad = int_set_del(f_pool, v1.val.ad, n);
@@ -1209,7 +1241,7 @@ interpret(struct f_inst *what)
{
/* Extended community list */
int arg_set = 0;
-
+
/* v2.val is either EC or EC-set */
if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
arg_set = 1;
@@ -1226,10 +1258,10 @@ interpret(struct f_inst *what)
runtime("Can't add set");
else if (!arg_set)
res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
- else
+ else
res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
break;
-
+
case 'd':
if (!arg_set)
res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
@@ -1353,7 +1385,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
}
break;
- case 'c':
+ case 'c':
switch (f1->aux) {
case T_PREFIX_SET:
@@ -1381,7 +1413,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
return 0;
break;
- case 'V':
+ case 'V':
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
return 0;
break;
@@ -1399,12 +1431,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case 'r': ONEARG; break;
case P('c','p'): ONEARG; break;
case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
- ONEARG;
+ ONEARG;
if (!i_same(f1->a2.p, f2->a2.p))
- return 0;
+ return 0;
f2->a2.p = f1->a2.p;
break;
- case P('c','v'): break; /* internal instruction */
+ case P('c','v'): break; /* internal instruction */
case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
case P('i','M'): TWOARGS; break;
case P('A','p'): TWOARGS; break;
@@ -1414,7 +1446,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case P('R','C'):
TWOARGS;
/* Does not really make sense - ROA check resuls may change anyway */
- if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
+ if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
((struct f_inst_roa_check *) f2)->rtc->name))
return 0;
break;