Hello, BIRD developers!

Currently there is no way in filter rules to match routes by interface name
and interface index.

However string comparison (=,!=,>,<,... operations), and pattern matching 
(using ~ operator) already implemented in filters, so expressions like:

if "eth0" ~ "eth*" || "eth1" = "eth1" then
 print "This pattern matches!";

already works.

Only one thing that is really needed is exposing attribute with name to filter 
which references route outgoing interface name and index. Of course all of 
these variables must be readonly.

Interface indexes are taken from kernel (at least on Linux, and FreeBSD) and 
represents interface number in system. Matching to indexes is not such 
reliable as matching with interface names, as indexes might change on 
interface addition/removal.

Currently only sink (blackhole, unreachable and prohibit) routes in BIRD
have no interface associated. Return an empty string and index equal to zero
(no real index in kernel) for such routes.


-- 
SP5474-RIPE
Sergey Popovich
diff -purN a/doc/bird.sgml b/doc/bird.sgml
--- a/doc/bird.sgml	2013-09-25 12:35:37.805081155 +0300
+++ b/doc/bird.sgml	2013-09-25 12:56:20.725342862 +0300
@@ -1238,6 +1238,21 @@ undefined value is regarded as empty cli
 	only to <cf/RTD_BLACKHOLE/, <cf/RTD_UNREACHABLE/ or
 	<cf/RTD_PROHIBIT/.
 
+	<tag><m/string/ ifname</tag>
+	Name of the outgoing interface. Standard string comparison operations
+	(e.g. <cf/=, !=, &lt;, &gt;, &lt;=, &gt;=/) also applicable to this attribute.
+	Additionaly matching <cf/&tilde;/ operator could be used to match value
+	against shell pattern like in <cf/interface/ directive. Sink routes
+	(like blackhole, unreachable or prohibit) has no interface associated
+	with it, so <cf/ifname/ returns an empty string for such routes. Read-only.
+
+	<tag><m/int/ ifindex</tag>
+	Index of the outgoing interface. System wide index of the interface.
+	May be used for interface matching, however indexes might change on
+	interface creation/removal. Same notes about sink routes as described
+	for <cf/ifname/ also applicable to this attribute and <cf/ifindex/ returns
+	zero for such routes. Read-only.
+
 	<tag><m/int/ igp_metric</tag>
 	The optional attribute that can be used to specify a distance
 	to the network for routes that do not have a native protocol
diff -purN a/filter/config.Y b/filter/config.Y
--- a/filter/config.Y	2013-09-25 12:35:37.805081155 +0300
+++ b/filter/config.Y	2013-09-25 12:34:55.975324066 +0300
@@ -259,7 +259,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNS
 	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
 	IF, THEN, ELSE, CASE,
 	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
-	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
+	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
+	PREFERENCE,
 	LEN,
 	DEFINED,
 	ADD, DELETE, CONTAINS, RESET,
@@ -687,6 +688,8 @@ static_attr:
  | SCOPE   { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = OFFSETOF(struct rta, scope);  $$->a1.i = 1; }
  | CAST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTC;   $$->a2.i = OFFSETOF(struct rta, cast); }
  | DEST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTD;   $$->a2.i = OFFSETOF(struct rta, dest);   $$->a1.i = 1; }
+ | IFNAME  { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = OFFSETOF(struct iface, name); }
+ | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT;        $$->a2.i = OFFSETOF(struct iface, index); }
  ;
 
 term:
diff -purN a/filter/filter.c b/filter/filter.c
--- a/filter/filter.c	2013-09-25 12:35:37.805081155 +0300
+++ b/filter/filter.c	2013-09-25 12:47:48.703794821 +0300
@@ -915,14 +915,24 @@ interpret(struct f_inst *what)
       res.type = f_inst_aux_f_type(what->aux);
 
       switch(res.type) {
+      case T_INT:
+	if (what->a2.i == OFFSETOF(struct iface, index))
+	  res.val.i = rta->iface ? rta->iface->index : 0;
+	else
+	  res.val.i = 0;
+	break;
       case T_IP:
 	res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
 	break;
       case T_ENUM:
 	res.val.i = * ((char *) rta + what->a2.i);
 	break;
-      case T_STRING:	/* Warning: this is a special case for proto attribute */
-	res.val.s = rta->proto->name;
+      case T_STRING:
+	if (what->a2.i == OFFSETOF(struct iface, name))
+	  res.val.s = rta->iface ? rta->iface->name : "";
+	else
+	  /* Warning: this is a special case for proto attribute */
+	  res.val.s = rta->proto->name;
 	break;
       case T_PREFIX:	/* Warning: this works only for prefix of network */
 	{

Reply via email to