On Tue, 2005-27-12 at 08:33 -0500, jamal wrote:

> Using explicit priorities is also "broken". Has been since day
> one - Alexey was planning it to fix it "some day". i.e if you
> add a second exact same rule with exactly the same prio, it will
> be lifo added. OTOH, if you dont specify a priority the kernel
> gives you one and it becomes unique that way.
> 
[..]
> The second step should be to fix iprule to set NLM_F_EXCL only
> when priority/preference/order using "ip rule .."
> 
> I dont think there would be any ABI breakages this way. 
> old binaries continue to set NLM_F_EXCL and would not be added
> if all tuples are exactly the same; and new binaries will set
> NLM_F_EXCL only if a priority is defined.
> 

Ok, since i have time .. heres an illustration on top of Gabor's patch.
Untested but compiles.

cheers,
jamal
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 0b298bb..a2842c0 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -159,6 +159,23 @@ void fib_rule_put(struct fib_rule *r)
 	}
 }
 
+static struct fib_rule* fib_rule_find(struct fib_rule *q)
+{
+	struct fib_rule *r;
+	for (r = fib_rules; r; r = r->r_next) {
+		if (r->r_src == q->r_src && r->r_srcmask == q->r_srcmask &&
+		    r->r_dst == q->r_dst && r->r_dstmask == q->r_dstmask &&
+		    r->r_tos == q->r_tos &&
+#ifdef CONFIG_IP_ROUTE_FWMARK
+		    r->r_fwmark == q->r_fwmark &&
+#endif
+		    r->r_preference == q->r_preference &&
+		    r->r_ifindex == q->r_ifindex)
+			return r;
+	}
+	return NULL;
+}
+
 int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct rtattr **rta = arg;
@@ -220,6 +237,10 @@ int inet_rtm_newrule(struct sk_buff *skb
 		memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
 #endif
 
+	if ((nlh->nlmsg_flags & NLM_F_EXCL) && fib_rule_find(new_r)) {
+		kfree(new_r);
+		return -EEXIST;
+	}
 	rp = &fib_rules;
 	if (!new_r->r_preference) {
 		r = fib_rules;
diff --git a/ip/iprule.c b/ip/iprule.c
index cfe252a..da7ab9f 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -208,7 +208,7 @@ static int iprule_modify(int cmd, int ar
 	req.r.rtm_type = RTN_UNSPEC;
 
 	if (cmd == RTM_NEWRULE) {
-		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+		req.n.nlmsg_flags |= NLM_F_CREATE;
 		req.r.rtm_type = RTN_UNICAST;
 	}
 
@@ -233,6 +233,7 @@ static int iprule_modify(int cmd, int ar
 			if (get_u32(&pref, *argv, 0))
 				invarg("preference value is invalid\n", *argv);
 			addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref);
+			req.n.nlmsg_flags |= NLM_F_EXCL;
 		} else if (strcmp(*argv, "tos") == 0) {
 			__u32 tos;
 			NEXT_ARG();

Reply via email to