diff --git a/doc/bird.sgml b/doc/bird.sgml index 86df0456..c5316d87 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1119,9 +1119,12 @@ foot). returns the last ASN (the source ASN) in path returns the last ASN in the non-aggregated part of the path returns the length of path code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; } | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; } + | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; } /* Communities */ /* This causes one shift/reduce conflict diff --git a/filter/filter.c b/filter/filter.c index 55062aca..eddf4228 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -1091,6 +1091,14 @@ interpret(struct f_inst *what) res.type = T_INT; res.val.i = as; break; + case P('a','L'): /* Get last ASN from non-aggregated part of AS PATH */ + ONEARG; + if (v1.type != T_PATH) + runtime( "AS path expected" ); + + res.type = T_INT; + res.val.i = as_path_get_last_nonaggregated(v1.val.ad); + break; case 'r': ONEARG; res = v1; diff --git a/nest/a-path.c b/nest/a-path.c index c9c5aefb..32e2d27e 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -220,7 +220,7 @@ as_path_get_last(struct adata *path, u32 *orig_as) p += BS * len; } break; - default: bug("as_path_get_first: Invalid path segment"); + default: bug("Invalid path segment"); } } @@ -229,6 +229,35 @@ as_path_get_last(struct adata *path, u32 *orig_as) return found; } +u32 +as_path_get_last_nonaggregated(struct adata *path) +{ + u8 *p = path->data; + u8 *q = p+path->length; + u32 res = 0; + int len; + + while (p