Hello,
some fib alias fixes:
- modify fib_find_alias to stop before the desired alias, even
if reaching different TOS. If no alias is found we have to append
at end of fn_alias.
- properly prepend/append new alias with same prefix/tos/prio
- use list_for_each_entry_continue
Signed-off-by: Julian Anastasov <ja@ssi.bg>
diff -ur v2.6.9-rc2-bk10/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
@@ -431,24 +431,20 @@returnNULL;}-/* Return the first fib alias matching TOS with-*prioritylessthanorequaltoPRIO.-*/+/* Return the first fib alias below TOS and after PRIO thresholds */staticstructfib_alias*fib_find_alias(structfib_node*fn,u8tos,u32prio){if(fn){structlist_head*head=&fn->fn_alias;-structfib_alias*fa,*prev_fa;+structfib_alias*fa;-prev_fa=NULL;list_for_each_entry(fa,head,fa_list){-if(fa->fa_tos!=tos)+if(fa->fa_tos>tos)continue;-prev_fa=fa;-if(prio<=fa->fa_info->fib_priority)-break;+if(fa->fa_info->fib_priority>=prio||+fa->fa_tos<tos)+returnfa;}-returnprev_fa;}returnNULL;}
- modify fib_find_alias to stop before the desired alias, even
if reaching different TOS. If no alias is found we have to append
at end of fn_alias.
- properly prepend/append new alias with same prefix/tos/prio
- use list_for_each_entry_continue
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Two things:
1) I applied a version of the list_for_each_entry_continue fix
I got privately from Alexey, can you repatch relative to
that? It is included below.
2) The fib_alias list is not meant at all to be sorted by TOS
value. Within a TOS it _is_ sorted by priority. This was
intentional, and I believe your changes assume I meant to
keep the "aliases ordered by TOS" property. I did not.
Please give test cases when posting fixes of this nature.
I wouldn't have to guess about #2 if you gave a bunch of
"ip route foo" commands that gave behavior you think is
incorrect.
Thanks.
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
# 2004/09/25 19:47:58-07:00 kuznet@ms2.inr.ac.ru
# [IPV4]: Fix fa_list walking in fib_hash.c
#
# Prevent accidently referencing f->fn_alias list
# head as a real fib_alias object.
#
# Signed-off-by: David S. Miller [off-list ref]
#
# net/ipv4/fib_hash.c
# 2004/09/25 19:47:27-07:00 kuznet@ms2.inr.ac.ru +4 -4
# [IPV4]: Fix fa_list walking in fib_hash.c
#
# Prevent accidently referencing f->fn_alias list
# head as a real fib_alias object.
#
# Signed-off-by: David S. Miller [off-list ref]
#
diff -Nru a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
Hello,
On Sat, 25 Sep 2004, David S. Miller wrote:
2) The fib_alias list is not meant at all to be sorted by TOS
value. Within a TOS it _is_ sorted by priority. This was
intentional, and I believe your changes assume I meant to
keep the "aliases ordered by TOS" property. I did not.
But it still needs one exception: the entries with TOS 0
must be at tail to allow fn_hash_lookup to match by TOS. With
random TOS insertion this is not guaranteed, the entries with
TOS=0 (wildcard) will match before the others.
So, I fixed it to allow the TOS subchains to be
in any order but always before the subchain with TOS 0.
Please give test cases when posting fixes of this nature.
I wouldn't have to guess about #2 if you gave a bunch of
"ip route foo" commands that gave behavior you think is
incorrect.
ok, I'm attaching 3 files: new diff, test script to add/del
entries in custom table and its output in another file (after
applying the patch). I'm using:
./rt.sh start
./rt.sh stop
Regards
--
Julian Anastasov [off-list ref]
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2004-09-26 08:14:49
Julian Anastasov [off-list ref] wrote:
But it still needs one exception: the entries with TOS 0
must be at tail to allow fn_hash_lookup to match by TOS. With
random TOS insertion this is not guaranteed, the entries with
TOS=0 (wildcard) will match before the others.
Good point.
prev_fa = NULL;
list_for_each_entry(fa, head, fa_list) {
if (fa->fa_tos != tos)
- continue;
+ {
+ if (!prev_fa && fa->fa_tos)
+ continue;
+ /* Stop at TOS 0 or after entries from our TOS */
+ return fa;
+ }
Well if we're doing this then we might as well keep it sorted by TOS.
It makes the code simpler, right?
I do not know for good reason to avoid order by TOS, may be
Dave can explain.
As for your last change, it is wrong:
prev_fa = NULL;
list_for_each_entry(fa, head, fa_list) {
- if (fa->fa_tos != tos)
- continue;
+ if (fa->fa_tos < tos)
here prev_fa can be NULL but we require to stop at fa.
It happens when we are creating first entry in our subchain.
+ break;
prev_fa = fa;
+ if (fa->fa_tos > tos)
+ continue;
if (prio <= fa->fa_info->fib_priority)
break;
here if fa is the last one it is wrong to return prev_fa!=NULL,
we need to return NULL (append) because we have to append
new entry in our subchain (which is last in this case).
}
Here is my understanding how should work fib_find_alias (already
implemented, refer to my first posting, the case where we sort by TOS).
Note that the logic is same as before fib_alias appeared:
- fib_find_alias can return exact match: the desired TOS & PRIO.
This is the first entry in a subchain where append and prepend
matter (NLM_F_APPEND).
- the return value should be used in this way: if NULL then we have
to append the new entry at end of list. Else, it is a fa with
fa_tos<desired_TOS || (fa_tos==desired_TOS && fib_priority >= desired PRIO)
We are going to insert the new entry before this fa (even if it is
not exact match, even if it is from next subchain). Saying it in
another way: use append only if there is no place to insert.
Sometimes we can add entry with metric less
than existing one but sometimes we have to insert new entry
between two subchains (fa points to first entry in next subchain).
The result: fa points to next subchain or somehere in our
subchain - the place to insert.
- list_add serves the purpose to insert between head and first
(fa and next fa/fn_alias), we need list_add_tail (insert before fa
or fn_alias, i.e. append at tail).
So, may be we need my 1st version of fib_find_alias plus
'fa->fa_tos == tos' plus list_add_tail?
Regards
--
Julian Anastasov [off-list ref]
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2004-09-26 12:32:34
Julian Anastasov [off-list ref] wrote:
As for your last change, it is wrong:
quoted
prev_fa = NULL;
list_for_each_entry(fa, head, fa_list) {
- if (fa->fa_tos != tos)
- continue;
+ if (fa->fa_tos < tos)
here prev_fa can be NULL but we require to stop at fa.
It happens when we are creating first entry in our subchain.
If fa->fa_tos < tos, then we should add the new entry before fa.
If prev_fa is not NULL, then adding after prev_fa is obviously
correct. If prev_fa is NULL, the caller will add it after the
head of the list which is also correct since fa must've been the
first element in the list.
quoted
+ break;
prev_fa = fa;
+ if (fa->fa_tos > tos)
+ continue;
if (prio <= fa->fa_info->fib_priority)
break;
here if fa is the last one it is wrong to return prev_fa!=NULL,
we need to return NULL (append) because we have to append
new entry in our subchain (which is last in this case).
I still haven't figured out what you mean here, but I've found a bug :)
When prio < fa->fa_info->fib_priority, this returns the wrong entry.
- fib_find_alias can return exact match: the desired TOS & PRIO.
This is the first entry in a subchain where append and prepend
matter (NLM_F_APPEND).
Ack.
- the return value should be used in this way: if NULL then we have
to append the new entry at end of list. Else, it is a fa with
Not quite. If it's NULL we add it at the *head* of the list. We
call list_add and not list_add_tail. Actually your patch changes the
list_add call to list_add_tail so your comment would be correct if your
patch had been applied :)
fa_tos<desired_TOS || (fa_tos==desired_TOS && fib_priority >= desired PRIO)
We are going to insert the new entry before this fa (even if it is
not exact match, even if it is from next subchain). Saying it in
another way: use append only if there is no place to insert.
Again this is only true if we apply your patch. As it is find_alias
returns (and is expected to return) the entry *before* where the new
entry should be added.
Whether it *should* be before or after is obviously a deep philosophical
question :)
So here are two patches to fix the fib_priority problem. The first one
returns the entry before as we do now while the second one returns the
entry afterwards.
Actually, I just noticed that this philosophical question does have
practical implications :) The list_for_each_entry_continue() loop in
fn_hash_delete will fail if fa is the entry before the correct position.
Therefore I withdraw my endorsement for the "entry before" interpretation :)
So patch 1 is only present for review purposes, please don't apply it.
Patch 2 is good as far as I can see. So,
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
-- patch 1
===== net/ipv4/fib_hash.c 1.26 vs edited =====
@@ -432,23 +432,23 @@}/* Return the first fib alias matching TOS with-*prioritylessthanorequaltoPRIO.+*thesamepriorityorthepointwherethenodeshouldbeinserted.*/staticstructfib_alias*fib_find_alias(structfib_node*fn,u8tos,u32prio){if(fn){structlist_head*head=&fn->fn_alias;-structfib_alias*fa,*prev_fa;+structfib_alias*fa;-prev_fa=NULL;list_for_each_entry(fa,head,fa_list){-if(fa->fa_tos!=tos)+if(fa->fa_tos<tos)+break;+if(fa->fa_tos>tos)continue;-prev_fa=fa;if(prio<=fa->fa_info->fib_priority)break;}-returnprev_fa;+returnfa;}returnNULL;}
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2004-09-26 12:35:57
On Sun, Sep 26, 2004 at 10:32:34PM +1000, Herbert Xu wrote:
Therefore I withdraw my endorsement for the "entry before" interpretation :)
So patch 1 is only present for review purposes, please don't apply it.
Patch 2 is good as far as I can see. So,
Hello,
attaching version with fib_alias ordered by TOS ...
On Sun, 26 Sep 2004, Herbert Xu wrote:
quoted
here prev_fa can be NULL but we require to stop at fa.
It happens when we are creating first entry in our subchain.
If fa->fa_tos < tos, then we should add the new entry before fa.
True, but in your patch2 you return fa after
list_for_each_entry which is not valid when the loop terminates.
Just change it to return the fa into the loop.
If prev_fa is not NULL, then adding after prev_fa is obviously
correct. If prev_fa is NULL, the caller will add it after the
May be there are two varaints when we do not return list_head
but fa:
- "insert before": find a place to "insert before" else add in tail
- "insert after": find a place to "insert after" else add in top
but as fib_find_alias is used also for deletion I do
not think we have many choices, we return the node to insert
before, as in the comment.
head of the list which is also correct since fa must've been the
first element in the list.
quoted
quoted
+ break;
prev_fa = fa;
+ if (fa->fa_tos > tos)
+ continue;
if (prio <= fa->fa_info->fib_priority)
break;
here if fa is the last one it is wrong to return prev_fa!=NULL,
we need to return NULL (append) because we have to append
new entry in our subchain (which is last in this case).
I still haven't figured out what you mean here, but I've found a bug :)
When prio < fa->fa_info->fib_priority, this returns the wrong entry.
Yes, this is one of the original problems :) If you have the
kernel running you can try the posted test script.
quoted
- the return value should be used in this way: if NULL then we have
to append the new entry at end of list. Else, it is a fa with
Not quite. If it's NULL we add it at the *head* of the list. We
call list_add and not list_add_tail. Actually your patch changes the
list_add call to list_add_tail so your comment would be correct if your
patch had been applied :)
It seems there are too many wishes currently in fib_find_alias.
list_add can be used for "insert after" but fa is declared to be for
"insert before fa". I think, fib_find_alias was originally designed
to be used for "insert before fa".
quoted
fa_tos<desired_TOS || (fa_tos==desired_TOS && fib_priority >= desired PRIO)
We are going to insert the new entry before this fa (even if it is
not exact match, even if it is from next subchain). Saying it in
another way: use append only if there is no place to insert.
Again this is only true if we apply your patch. As it is find_alias
returns (and is expected to return) the entry *before* where the new
entry should be added.
Yes, "insert before fa", then why list_add is used?
Whether it *should* be before or after is obviously a deep philosophical
question :)
So here are two patches to fix the fib_priority problem. The first one
returns the entry before as we do now while the second one returns the
entry afterwards.
Actually, I just noticed that this philosophical question does have
practical implications :) The list_for_each_entry_continue() loop in
fn_hash_delete will fail if fa is the entry before the correct position.
There are simply no alternatives :) I'm attaching version
with TOS ordering for review.
Therefore I withdraw my endorsement for the "entry before" interpretation :)
So patch 1 is only present for review purposes, please don't apply it.
Patch 2 is good as far as I can see. So,
return fa in loop
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2004-09-26 21:23:16
Julian Anastasov [off-list ref] wrote:
True, but in your patch2 you return fa after
list_for_each_entry which is not valid when the loop terminates.
Just change it to return the fa into the loop.
You're right, we dereference it in fn_hash_insert.
From: Robert Olsson <hidden> Date: 2004-09-27 12:09:22
Herbert Xu writes:
> Robert Olsson [off-list ref] wrote:
> >
> > I'll guess struct fib_alias should not be defined in fib_hash.c to
> > support pluggable lookup algorithms.
>
> Should one turn up then we can move it out :)
Do. :-) Seems fib_find_alias should be moved out as well.
Cheers.
--ro