On 24/02/16(Wed) 18:37, Jean-Daniel Dupas wrote:
> >Synopsis:      ECMP routing ignore dest addr when choosing a route
> >Category:      kernel
> >Environment:
>         System      : OpenBSD 5.9
>         Details     : OpenBSD 5.9 (DEBUG) #0: Wed Feb 24 14:29:57 CET 2016
>                          
> r...@gw1.xooloo.io:/usr/src/sys/arch/amd64/compile/DEBUG
> 
>         Architecture: OpenBSD.amd64
>         Machine     : amd64
> >Description:
>         Since OpenBSD 5.8, I can't managed to get a proper balancing when 
> using equal-cost multipath. It looks like all queries from a source are 
> routed using the same route.
>         I'm not very familiar with the kernel code, so I may be wrong, but 
> after launching a debug session, I think that the issue is in rtable_match(). 
> That function first resolve the radix_node using the actual dest address, and 
> then compute a hash for mpath using the radix_node key instead of the dest 
> address. As the radix node is the default route node (in my case), the radix 
> node key is always 0.0.0.0. So the hash end up having always the same value, 
> and the route selected for mpatch is always the same.

Thanks for the bug report and great analysis.  Does the diff below fix
the issue for you?

Index: net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.293
diff -u -p -r1.293 route.c
--- net/route.c 21 Dec 2015 10:51:55 -0000      1.293
+++ net/route.c 24 Feb 2016 17:54:13 -0000
@@ -283,9 +283,8 @@ struct rtentry *_rtalloc(struct sockaddr
 } while (0)
 
 int
-rt_hash(struct rtentry *rt, uint32_t *src)
+rt_hash(struct rtentry *rt, struct sockaddr *dst, uint32_t *src)
 {
-       struct sockaddr *dst = rt_key(rt);
        uint32_t a, b, c;
 
        if (src == NULL || !rtisvalid(rt) || !ISSET(rt->rt_flags, RTF_MPATH))
Index: net/route.h
===================================================================
RCS file: /cvs/src/sys/net/route.h,v
retrieving revision 1.131
diff -u -p -r1.131 route.h
--- net/route.h 18 Jan 2016 15:38:52 -0000      1.131
+++ net/route.h 24 Feb 2016 17:54:57 -0000
@@ -378,7 +378,7 @@ unsigned long                rt_timer_queue_count(str
 void                    rt_timer_timer(void *);
 
 int     rtisvalid(struct rtentry *);
-int     rt_hash(struct rtentry *, uint32_t *);
+int     rt_hash(struct rtentry *, struct sockaddr *, uint32_t *);
 #ifdef SMALL_KERNEL
 #define         rtalloc_mpath(dst, s, rid) rtalloc((dst), RT_RESOLVE, (rid))
 #else
Index: net/rtable.c
===================================================================
RCS file: /cvs/src/sys/net/rtable.c,v
retrieving revision 1.38
diff -u -p -r1.38 rtable.c
--- net/rtable.c        18 Jan 2016 18:27:12 -0000      1.38
+++ net/rtable.c        24 Feb 2016 17:54:37 -0000
@@ -367,7 +367,7 @@ rtable_match(unsigned int rtableid, stru
 
 #ifndef SMALL_KERNEL
        /* Gateway selection by Hash-Threshold (RFC 2992) */
-       if ((hash = rt_hash(rt, src)) != -1) {
+       if ((hash = rt_hash(rt, dst, src)) != -1) {
                struct rtentry          *mrt = rt;
                int                      threshold, npaths = 1;
 
@@ -617,7 +617,7 @@ rtable_match(unsigned int rtableid, stru
 
 #ifndef SMALL_KERNEL
        /* Gateway selection by Hash-Threshold (RFC 2992) */
-       if ((hash = rt_hash(rt, src)) != -1) {
+       if ((hash = rt_hash(rt, dst, src)) != -1) {
                struct rtentry          *mrt;
                struct srpl_iter         i;
                int                      threshold, npaths = 0;

Reply via email to