Extends delete/filter operators to work no bgp_paths.
This commit is contained in:
parent
8a112d8ba2
commit
bff9ce5130
5 changed files with 112 additions and 3 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ~ [(*,*)];
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue