]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Implement last_nonaggregated operator on bgp_path
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 16 Feb 2016 16:33:58 +0000 (17:33 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 16 Feb 2016 16:33:58 +0000 (17:33 +0100)
doc/bird.sgml
filter/config.Y
filter/filter.c
nest/a-path.c
nest/attrs.h

index 86df0456907e3038c029fd85725baeba3ad55f26..c5316d87340ea72733188fa9f027724b219644c5 100644 (file)
@@ -1119,9 +1119,12 @@ foot).
 
        <cf><m/P/.last</cf> returns the last ASN (the source ASN) in path <m/P/.
 
+       <cf><m/P/.last_nonaggregated</cf> returns the last ASN in the non-aggregated part of the path <m/P/.
+
        Both <cf/first/ and <cf/last/ return zero if there is no appropriate
        ASN, for example if the path contains an AS set element as the first (or
-       the last) part.
+       the last) part. If the path ends with an AS set, <cf/last_nonaggregated/
+       may be used to get last ASN before any AS set.
 
        <cf><m/P/.len</cf> returns the length of path <m/P/.
 
index 7eb2c0a37324d78bca1511fc85f2fe778b05d049..b94f5dfff0be4fe7abb22df66fd3b57111bed64e 100644 (file)
@@ -283,7 +283,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        LEN,
        DEFINED,
        ADD, DELETE, CONTAINS, RESET,
-       PREPEND, FIRST, LAST, MATCH,
+       PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
        ROA_CHECK,
        EMPTY,
        FILTER, WHERE, EVAL)
@@ -752,6 +752,7 @@ term:
  | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->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
index 55062acadec94f9309ca21588630876a460da6e5..eddf4228cb6d94243d9d863e51c76d20412d6892 100644 (file)
@@ -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;
index c9c5aefb5a71058c9980deb4b5ad350cf1d10ee2..32e2d27eb184de7638e116bfcbe366513a830af9 100644 (file)
@@ -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<q)
+    {
+      switch (*p++)
+       {
+       case AS_PATH_SET:
+         return res;
+
+       case AS_PATH_SEQUENCE:
+         if (len = *p++)
+           res = get_as(p + BS * (len - 1));
+         p += BS * len;
+         break;
+
+       default: bug("Invalid path segment");
+       }
+    }
+
+  return res;
+}
+
+
 int
 as_path_get_first(struct adata *path, u32 *last_as)
 {
index 1d005a6a9269c8c6ccf8cbe923ac3bcfab404f8f..0171c6a8fe509e8633688079a6a97864954aa459 100644 (file)
@@ -35,6 +35,7 @@ int as_path_getlen(struct adata *path);
 int as_path_getlen_int(struct adata *path, int bs);
 int as_path_get_first(struct adata *path, u32 *orig_as);
 int as_path_get_last(struct adata *path, u32 *last_as);
+u32 as_path_get_last_nonaggregated(struct adata *path);
 int as_path_contains(struct adata *path, u32 as, int min);
 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);