Extends delete/filter operators to work no bgp_paths.

This commit is contained in:
Ondrej Zajicek 2013-08-15 01:06:47 +02:00
parent 8a112d8ba2
commit bff9ce5130
5 changed files with 112 additions and 3 deletions

View file

@ -1033,10 +1033,23 @@ incompatible with each other (that is to prevent you from shooting in the foot).
<cf><m/P/.len</cf> returns the length of path <m/P/. <cf><m/P/.len</cf> returns the length of path <m/P/.
<cf>prepend(<m/P/,<m/A/)</cf> prepends ASN <m/A/ to path <m/P/ and returns the result. <cf>prepend(<m/P/,<m/A/)</cf> prepends ASN <m/A/ to path
<m/P/ and returns the result.
<cf>delete(<m/P/,<m/A/)</cf> deletes all instances of ASN
<m/A/ from from path <m/P/ and returns the result.
<m/A/ may also be an integer set, in that case the
operator deletes all ASNs from path <m/P/ that are also
members of set <m/A/.
<cf>filter(<m/P/,<m/A/)</cf> deletes all ASNs from path
<m/P/ that are not members of integer set <m/A/.
I.e., <cf/filter/ do the same as <cf/delete/ with inverted
set <m/A/.
Statement <cf><m/P/ = prepend(<m/P/, <m/A/);</cf> can be shortened to Statement <cf><m/P/ = prepend(<m/P/, <m/A/);</cf> can be shortened to
<cf><m/P/.prepend(<m/A/);</cf> if <m/P/ is appropriate route attribute <cf><m/P/.prepend(<m/A/);</cf> if <m/P/ is appropriate route attribute
(for example <cf/bgp_path/). (for example <cf/bgp_path/). Similarly for <cf/delete/ and <cf/filter/.
<tag/bgpmask/ <tag/bgpmask/
BGP masks are patterns used for BGP path matching BGP masks are patterns used for BGP path matching

View file

@ -1165,7 +1165,34 @@ interpret(struct f_inst *what)
case P('C','a'): /* (Extended) Community list add or delete */ case P('C','a'): /* (Extended) Community list add or delete */
TWOARGS; 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 */ /* Community (or cluster) list */
struct f_val dummy; struct f_val dummy;

View file

@ -104,6 +104,8 @@ eclist el2;
print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4); 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 "Should be true: ", p2.len = 5, " ", p2.first = 5, " ", p2.last = 1;
print "5 = ", p2.len; print "5 = ", p2.len;
print "Delete 3: ", delete(p2, 3);
print "Filter 1-3: ", filter(p2, [1..3]);
pm1 = [= 1 2 * 3 4 5 =]; pm1 = [= 1 2 * 3 4 5 =];
p2 = prepend( + empty +, 5 ); p2 = prepend( + empty +, 5 );
@ -113,6 +115,8 @@ eclist el2;
p2 = prepend( p2, 2 ); p2 = prepend( p2, 2 );
p2 = prepend( p2, 1 ); p2 = prepend( p2, 1 );
print "Should be true: ", p2 ~ pm1, " ", p2, " ", pm1; print "Should be true: ", p2 ~ pm1, " ", p2, " ", pm1;
print "Delete 3: ", delete(p2, 3);
print "Delete 4-5: ", delete(p2, [4..5]);
l = - empty -; l = - empty -;
print "Should be false in this special case: ", l ~ [(*,*)]; print "Should be false in this special case: ", l ~ [(*,*)];

View file

@ -287,6 +287,69 @@ as_path_match_set(struct adata *path, struct f_tree *set)
return 0; return 0;
} }
struct adata *
as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos)
{
if (!path)
return NULL;
int len = path->length;
u8 *p = path->data;
u8 *q = path->data + len;
u8 *d, *d2;
int i, bt, sn, dn;
u8 buf[len];
d = buf;
while (p<q)
{
/* Read block header (type and length) */
bt = p[0];
sn = p[1];
dn = 0;
p += 2;
d2 = d + 2;
for (i = 0; i < sn; i++)
{
u32 as = get_as(p);
int match;
if (set)
match = !!find_tree(set, (struct f_val){T_INT, .val.i = as});
else
match = (as == key);
if (match == pos)
{
put_as(d2, as);
d2 += BS;
dn++;
}
p += BS;
}
if (dn > 0)
{
/* Nonempty block, set block header and advance */
d[0] = bt;
d[1] = dn;
d = d2;
}
}
int nl = d - buf;
if (nl == path->length)
return path;
struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl);
res->length = nl;
memcpy(res->data, buf, nl);
return res;
}
struct pm_pos struct pm_pos
{ {

View file

@ -37,6 +37,8 @@ int as_path_get_first(struct adata *path, u32 *orig_as);
int as_path_get_last(struct adata *path, u32 *last_as); int as_path_get_last(struct adata *path, u32 *last_as);
int as_path_is_member(struct adata *path, u32 as); int as_path_is_member(struct adata *path, u32 as);
int as_path_match_set(struct adata *path, struct f_tree *set); int as_path_match_set(struct adata *path, struct f_tree *set);
struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos);
#define PM_ASN 0 #define PM_ASN 0
#define PM_QUESTION 1 #define PM_QUESTION 1