[PATCH 07/12] Introduce try ... catch statement to handle filter runtime errors.

Sergey Popovich popovich_sergei at mail.ru
Mon Sep 30 20:33:45 CEST 2013


There are two types of filter errors: which could be checked and
reported on configuration file parsing and runtime, which could
not be checked at compile time but could be only triggered at runtime
filter statement evaluation.

Currently there no mechanism in BIRD to branch to alternative action
(or gust ignore) in case of filter runtime error.

This patch introduces try ... catch statement to catch an runtime
errors and execute alternative action.
---
 doc/bird.sgml   |   23 ++++++++++++++++++++++-
 filter/config.Y |    8 +++++++-
 filter/filter.c |    7 +++++++
 3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/doc/bird.sgml b/doc/bird.sgml
index d1d7860..65fc207 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1139,7 +1139,7 @@ specify a prefix and an ASN as arguments.
  <sect>Control structures
 -<p>Filters support two control structures: conditions and case
switches. +<p>Filters support tree control structures: conditions, case
switches and filter runtime error handing.
  <p>Syntax of a condition is: <cf>if
 <M>boolean expression</M> then <M>command1</M>; else
<M>command2</M>;</cf> and you can use <cf>{
@@ -1167,6 +1167,27 @@ if 1234 = i then printn "."; else {
 }
 </code>
 +<p>Syntax of filter runtime error handing statement is:
+<cf>try <m/command1/ catch <m/command2/</cf>, where <cf/try/ statement
+executes <cf><m/command1/</cf> and if it throws an filter runtime error
+(for example dynamic attribute not present), <cf/catch/ statement
+executes <cf><m/command2/</cf>.
+An log entry is still created for statement in <cf><m/command1/</cf> which
+throws an error.
+
+<p>Here is example on how to use <cf>try ... catch</cf> statement:
+
+<code>
+try {
+	# If neighbor is not on directly connected subnet, or it denotes
+	# host itself: generate runtime error
+	gw = 192.0.2.2;
+} catch {
+	# Setting gw unsuccessfully; mark route as blackhole
+	dest = RTD_BLACKHOLE;
+}
+</code>
+
 <sect>Route attributes
  <p>A filter is implicitly passed a route, and it can access its
diff --git a/filter/config.Y b/filter/config.Y
index faa02f5..42b9e19 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -263,7 +263,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 	ACCEPT, REJECT, ERROR, QUITBIRD,
 	INT, BOOL, IP, PREFIX, PAIR, QUAD, EC,
 	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
-	IF, THEN, ELSE, CASE,
+	IF, THEN, ELSE, CASE, TRY, CATCH,
 	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
 	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
 	PREFERENCE,
@@ -826,6 +826,12 @@ cmd:
      $$->a1.p = i;
      $$->a2.p = $6;
    }
+ | TRY block CATCH block {
+     $$ = f_new_inst();
+     $$->code = P('T','C');
+     $$->a1.p = $2;
+     $$->a2.p = $4;
+   }
  | SYM '=' term ';' {
      $$ = f_new_inst();
      DBG( "Ook, we'll set value\n" );
diff --git a/filter/filter.c b/filter/filter.c
index 8164ead..5610f3f 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -1323,6 +1323,12 @@ interpret(struct f_inst *what)
     res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as);
     break;
 +  case P('T','C'):
+    res = interpret(what->a1.p);
+    if ((res.type == T_RETURN) && (res.val.i == F_ERROR))
+      ARG(res, a2.p);
+    break;
+
   default:
     bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
   }
@@ -1453,6 +1459,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
     if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,  	
((struct f_inst_roa_check *) f2)->rtc->name))
       return 0;
+  case P('T','C'): TWOARGS; break;
     break;
   default:
     bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
-- 
1.7.10.4



More information about the Bird-users mailing list