fib_rules: add route suppression based on ifgroup
authorStefan Tomanek <stefan.tomanek@wertarbyte.de>
Fri, 2 Aug 2013 15:19:56 +0000 (17:19 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 Aug 2013 22:24:22 +0000 (15:24 -0700)
This change adds the ability to suppress a routing decision based upon the
interface group the selected interface belongs to. This allows it to
exclude specific devices from a routing decision.

Signed-off-by: Stefan Tomanek <stefan.tomanek@wertarbyte.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/fib_rules.h
include/uapi/linux/fib_rules.h
net/core/fib_rules.c
net/ipv4/fib_rules.c
net/ipv6/fib6_rules.c

index 2f286dce92595b3712ac7c44c7267607f9b81ec6..d13c461b4b59a1d13923e7017abff7dfa9268009 100644 (file)
@@ -18,6 +18,7 @@ struct fib_rule {
        u32                     pref;
        u32                     flags;
        u32                     table;
+       int                     suppress_ifgroup;
        u8                      table_prefixlen_min;
        u8                      action;
        u32                     target;
@@ -84,6 +85,7 @@ struct fib_rules_ops {
        [FRA_FWMASK]    = { .type = NLA_U32 }, \
        [FRA_TABLE]     = { .type = NLA_U32 }, \
        [FRA_TABLE_PREFIXLEN_MIN] = { .type = NLA_U8 }, \
+       [FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
        [FRA_GOTO]      = { .type = NLA_U32 }
 
 static inline void fib_rule_get(struct fib_rule *rule)
index 59cd31b3455ea1cf9afe039098bf3b0bfa5b0e95..63e31166e85bfcab6b0abf8d8d999578501dd43e 100644 (file)
@@ -44,7 +44,7 @@ enum {
        FRA_FWMARK,     /* mark */
        FRA_FLOW,       /* flow/class id */
        FRA_UNUSED6,
-       FRA_UNUSED7,
+       FRA_SUPPRESS_IFGROUP,
        FRA_TABLE_PREFIXLEN_MIN,
        FRA_TABLE,      /* Extended table id */
        FRA_FWMASK,     /* mask for netfilter mark */
index 2ef5040c99c8d509571071df339bfefb9460c06a..5040a61bf28a4185cecacc9097c4d751c0e61fb2 100644 (file)
@@ -343,6 +343,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
        if (tb[FRA_TABLE_PREFIXLEN_MIN])
                rule->table_prefixlen_min = nla_get_u8(tb[FRA_TABLE_PREFIXLEN_MIN]);
 
+       if (tb[FRA_SUPPRESS_IFGROUP])
+               rule->suppress_ifgroup = nla_get_u32(tb[FRA_SUPPRESS_IFGROUP]);
+
        if (!tb[FRA_PRIORITY] && ops->default_pref)
                rule->pref = ops->default_pref(ops);
 
@@ -529,6 +532,7 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
                         + nla_total_size(4) /* FRA_PRIORITY */
                         + nla_total_size(4) /* FRA_TABLE */
                         + nla_total_size(1) /* FRA_TABLE_PREFIXLEN_MIN */
+                        + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */
                         + nla_total_size(4) /* FRA_FWMARK */
                         + nla_total_size(4); /* FRA_FWMASK */
 
@@ -588,6 +592,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
            (rule->target &&
             nla_put_u32(skb, FRA_GOTO, rule->target)))
                goto nla_put_failure;
+
+       if (rule->suppress_ifgroup != -1) {
+               if (nla_put_u32(skb, FRA_SUPPRESS_IFGROUP, rule->suppress_ifgroup))
+                       goto nla_put_failure;
+       }
+
        if (ops->fill(rule, skb, frh) < 0)
                goto nla_put_failure;
 
index 9f2906679d1f0c874245381d4b338ce8b1d3965b..b78fd28970c9f9384503296d8d81af55ab381b66 100644 (file)
@@ -103,16 +103,27 @@ errout:
 
 static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
 {
+       struct fib_result *result = (struct fib_result *) arg->result;
+       struct net_device *dev = result->fi->fib_dev;
+
        /* do not accept result if the route does
         * not meet the required prefix length
         */
-       struct fib_result *result = (struct fib_result *) arg->result;
-       if (result->prefixlen < rule->table_prefixlen_min) {
-               if (!(arg->flags & FIB_LOOKUP_NOREF))
-                       fib_info_put(result->fi);
-               return true;
-       }
+       if (result->prefixlen < rule->table_prefixlen_min)
+               goto suppress_route;
+
+       /* do not accept result if the route uses a device
+        * belonging to a forbidden interface group
+        */
+       if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
+               goto suppress_route;
+
        return false;
+
+suppress_route:
+       if (!(arg->flags & FIB_LOOKUP_NOREF))
+               fib_info_put(result->fi);
+       return true;
 }
 
 static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
index 554a4fbabfb3b2dbf9ab4418e3b4c0683c0580d1..36283267e2f88ee9099a0a3a50d70561e0d812a3 100644 (file)
@@ -122,14 +122,24 @@ out:
 static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
 {
        struct rt6_info *rt = (struct rt6_info *) arg->result;
+       struct net_device *dev = rt->rt6i_idev->dev;
        /* do not accept result if the route does
         * not meet the required prefix length
         */
-       if (rt->rt6i_dst.plen < rule->table_prefixlen_min) {
+       if (rt->rt6i_dst.plen < rule->table_prefixlen_min)
+               goto suppress_route;
+
+       /* do not accept result if the route uses a device
+        * belonging to a forbidden interface group
+        */
+       if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
+               goto suppress_route;
+
+       return false;
+
+suppress_route:
                ip6_rt_put(rt);
                return true;
-       }
-       return false;
 }
 
 static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)