From 3dfbcc411e461db51a1ac1aa1c6ebe2c5a0275a0 Mon Sep 17 00:00:00 2001
From: Thomas Graf <tgraf@suug.ch>
Date: Thu, 9 Nov 2006 15:23:20 -0800
Subject: [PATCH] [NET] rules: Add support to invert selectors

Introduces a new flag FIB_RULE_INVERT causing rules to apply
if the specified selector doesn't match.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/fib_rules.h |  1 +
 net/core/fib_rules.c      | 24 +++++++++++++++++-------
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
index adcdfbdd14d5..8270aac2aa5d 100644
--- a/include/linux/fib_rules.h
+++ b/include/linux/fib_rules.h
@@ -6,6 +6,7 @@
 
 /* rule is permanent, and cannot be deleted */
 #define FIB_RULE_PERMANENT	1
+#define FIB_RULE_INVERT		2
 
 struct fib_rule_hdr
 {
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index da91bf2e6151..4148e274a204 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -107,6 +107,22 @@ out:
 
 EXPORT_SYMBOL_GPL(fib_rules_unregister);
 
+static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
+			  struct flowi *fl, int flags)
+{
+	int ret = 0;
+
+	if (rule->ifindex && (rule->ifindex != fl->iif))
+		goto out;
+
+	if ((rule->mark ^ fl->mark) & rule->mark_mask)
+		goto out;
+
+	ret = ops->match(rule, fl, flags);
+out:
+	return (rule->flags & FIB_RULE_INVERT) ? !ret : ret;
+}
+
 int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
 		     int flags, struct fib_lookup_arg *arg)
 {
@@ -116,13 +132,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
 	rcu_read_lock();
 
 	list_for_each_entry_rcu(rule, ops->rules_list, list) {
-		if (rule->ifindex && (rule->ifindex != fl->iif))
-			continue;
-
-		if ((rule->mark ^ fl->mark) & rule->mark_mask)
-			continue;
-
-		if (!ops->match(rule, fl, flags))
+		if (!fib_rule_match(rule, ops, fl, flags))
 			continue;
 
 		err = ops->action(rule, fl, flags, arg);
-- 
2.34.1