diff options
Diffstat (limited to 'sys/net/radix_mpath.c')
-rw-r--r-- | sys/net/radix_mpath.c | 43 |
1 files changed, 27 insertions, 16 deletions
diff --git a/sys/net/radix_mpath.c b/sys/net/radix_mpath.c index 8d94d01..9be01d2 100644 --- a/sys/net/radix_mpath.c +++ b/sys/net/radix_mpath.c @@ -77,15 +77,18 @@ rn_mpath_next(struct radix_node *rn) return NULL; } -u_int32_t +uint32_t rn_mpath_count(struct radix_node *rn) { - u_int32_t i; - - i = 1; - while ((rn = rn_mpath_next(rn)) != NULL) - i++; - return i; + uint32_t i = 0; + struct rtentry *rt; + + while (rn != NULL) { + rt = (struct rtentry *)rn; + i += rt->rt_rmx.rmx_weight; + rn = rn_mpath_next(rn); + } + return (i); } struct rtentry * @@ -256,10 +259,12 @@ different: } void -rtalloc_mpath_fib(struct route *ro, u_int32_t hash, u_int fibnum) +rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum) { struct radix_node *rn0, *rn; u_int32_t n; + struct rtentry *rt; + int64_t weight; /* * XXX we don't attempt to lookup cached route again; what should @@ -284,25 +289,31 @@ rtalloc_mpath_fib(struct route *ro, u_int32_t hash, u_int fibnum) /* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */ hash += hashjitter; hash %= n; - while (hash-- > 0 && rn) { + for (weight = abs((int32_t)hash), rt = ro->ro_rt; + weight >= rt->rt_rmx.rmx_weight && rn; + weight -= rt->rt_rmx.rmx_weight) { + /* stay within the multipath routes */ if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask) break; rn = rn->rn_dupedkey; + rt = (struct rtentry *)rn; } - /* XXX try filling rt_gwroute and avoid unreachable gw */ - /* if gw selection fails, use the first match (default) */ + /* gw selection has failed - there must be only zero weight routes */ if (!rn) { RT_UNLOCK(ro->ro_rt); + ro->ro_rt = NULL; return; } - - RTFREE_LOCKED(ro->ro_rt); - ro->ro_rt = (struct rtentry *)rn; - RT_LOCK(ro->ro_rt); - RT_ADDREF(ro->ro_rt); + if (ro->ro_rt != rt) { + RTFREE_LOCKED(ro->ro_rt); + ro->ro_rt = (struct rtentry *)rn; + RT_LOCK(ro->ro_rt); + RT_ADDREF(ro->ro_rt); + + } RT_UNLOCK(ro->ro_rt); } |