]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Extends delete/filter operators to work no bgp_paths.
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 14 Aug 2013 23:06:47 +0000 (01:06 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 14 Aug 2013 23:06:47 +0000 (01:06 +0200)
doc/bird.sgml
filter/filter.c
filter/test.conf
nest/a-path.c
nest/attrs.h

index 7db9fad263c47e6084238db9213196793d872b13..3cd80c3217404f8f3348eb7e4a0e3d01de6f6b6e 100644 (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>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
index 98bae331987a1b0c59ff105bd137fdb0bb2bd788..25587e0fe0a649640a124cbd763b295ae5223d11 100644 (file)
@@ -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;
index 4f40abff0136861f2c7ddb4502673f00dd21f20c..048983b593afe2319c8c795ebcc8725d8a8baee7 100644 (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.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 ~ [(*,*)];
index 712e77a38187bc959a079102c5a17665bfbe3e3c..b181298178896c4bfb889ca676c5fe3bad7008a8 100644 (file)
@@ -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
 {
index 12f2fcf467c3bd478f19fb1cfd7d1924bc643da5..44a23e18965927ddea09331b1d9387e65fe4dcf1 100644 (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_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