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();