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>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
|
||||
<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/
|
||||
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 */
|
||||
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;
|
||||
|
|
|
@ -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.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 );
|
||||
|
@ -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 ~ [(*,*)];
|
||||
|
|
|
@ -287,6 +287,69 @@ as_path_match_set(struct adata *path, struct f_tree *set)
|
|||
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
|
||||
{
|
||||
|
|
|
@ -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_is_member(struct adata *path, u32 as);
|
||||
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_QUESTION 1
|
||||
|
|
Loading…
Reference in a new issue