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