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;