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/=, !=, <, >, <=, >=/) also applicable to this attribute.
+ Additionaly matching <cf/˜/ 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 */
{