On 25/10/15(Sun) 16:21, Sebastian Benoit wrote: > Martin Pieuchot(m...@openbsd.org) on 2015.10.25 16:14:27 +0100: > > Diff below merges the guts of rtable_mpath_match() into rtable_lookup(). > > As for the previous rtable_mpath_* diff this is a step towards MPATH by > > default. > > > > This diff introduces a behavior change for RTM_GET. If multiple route > > exists a gateway MUST be specified and the first one in the tree won't > > be automagically selected by the kernel.
After discussion here's a diff that do almost the same refactoring but without introducing a behavior change. ok? Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.398 diff -u -p -r1.398 if.c --- net/if.c 25 Oct 2015 21:58:04 -0000 1.398 +++ net/if.c 26 Oct 2015 19:13:28 -0000 @@ -2360,7 +2360,7 @@ if_group_egress_build(void) bzero(&sa_in, sizeof(sa_in)); sa_in.sin_len = sizeof(sa_in); sa_in.sin_family = AF_INET; - rt0 = rtable_lookup(0, sintosa(&sa_in), sintosa(&sa_in)); + rt0 = rtable_lookup(0, sintosa(&sa_in), sintosa(&sa_in), NULL, RTP_ANY); if (rt0 != NULL) { rt = rt0; do { @@ -2377,7 +2377,8 @@ if_group_egress_build(void) #ifdef INET6 bcopy(&sa6_any, &sa_in6, sizeof(sa_in6)); - rt0 = rtable_lookup(0, sin6tosa(&sa_in6), sin6tosa(&sa_in6)); + rt0 = rtable_lookup(0, sin6tosa(&sa_in6), sin6tosa(&sa_in6), NULL, + RTP_ANY); if (rt0 != NULL) { rt = rt0; do { Index: net/route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.265 diff -u -p -r1.265 route.c --- net/route.c 25 Oct 2015 16:25:23 -0000 1.265 +++ net/route.c 26 Oct 2015 19:14:45 -0000 @@ -733,15 +733,11 @@ rtrequest1(int req, struct rt_addrinfo * switch (req) { case RTM_DELETE: rt = rtable_lookup(tableid, info->rti_info[RTAX_DST], - info->rti_info[RTAX_NETMASK]); + info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY], + prio); if (rt == NULL) return (ESRCH); #ifndef SMALL_KERNEL - rt = rtable_mpath_match(tableid, rt, - info->rti_info[RTAX_GATEWAY], prio); - if (rt == NULL) - return (ESRCH); - /* * If we got multipath routes, we require users to specify * a matching gateway. Index: net/rtable.c =================================================================== RCS file: /cvs/src/sys/net/rtable.c,v retrieving revision 1.15 diff -u -p -r1.15 rtable.c --- net/rtable.c 25 Oct 2015 14:48:51 -0000 1.15 +++ net/rtable.c 26 Oct 2015 19:11:50 -0000 @@ -249,7 +249,7 @@ rtable_free(unsigned int rtableid) struct rtentry * rtable_lookup(unsigned int rtableid, struct sockaddr *dst, - struct sockaddr *mask) + struct sockaddr *mask, struct sockaddr *gateway, uint8_t prio) { struct radix_node_head *rnh; struct radix_node *rn; @@ -264,6 +264,16 @@ rtable_lookup(unsigned int rtableid, str return (NULL); rt = ((struct rtentry *)rn); + +#ifndef SMALL_KERNEL + if (rnh->rnh_multipath) { + rt = rt_mpath_matchgate(rt, gateway, prio); + if (rt == NULL) + return (NULL); + } + +#endif /* !SMALL_KERNEL */ + rtref(rt); return (rt); @@ -372,26 +382,6 @@ rtable_mpath_capable(unsigned int rtable return (rnh->rnh_multipath); } -struct rtentry * -rtable_mpath_match(unsigned int rtableid, struct rtentry *rt0, - struct sockaddr *gateway, uint8_t prio) -{ - struct radix_node_head *rnh; - struct rtentry *rt; - - rnh = rtable_get(rtableid, rt_key(rt0)->sa_family); - if (rnh == NULL || rnh->rnh_multipath == 0) - return (rt0); - - rt = rt_mpath_matchgate(rt0, gateway, prio); - - if (rt != NULL) - rtref(rt); - rtfree(rt0); - - return (rt); -} - /* Gateway selection by Hash-Threshold (RFC 2992) */ struct rtentry * rtable_mpath_select(struct rtentry *rt, uint32_t hash) @@ -457,7 +447,7 @@ rtable_free(unsigned int rtableid) struct rtentry * rtable_lookup(unsigned int rtableid, struct sockaddr *dst, - struct sockaddr *mask) + struct sockaddr *mask, struct sockaddr *gateway, uint8_t prio) { struct art_root *ar; struct art_node *an; @@ -489,7 +479,25 @@ rtable_lookup(unsigned int rtableid, str if (an == NULL) return (NULL); +#ifdef SMALL_KERNEL rt = LIST_FIRST(&an->an_rtlist); +#else + LIST_FOREACH(rt, &an->an_rtlist, rt_next) { + if (prio != RTP_ANY && + (rt->rt_priority & RTP_MASK) != (prio & RTP_MASK)) + continue; + + if (gateway == NULL) + break; + + if (rt->rt_gateway->sa_len == gateway->sa_len && + memcmp(rt->rt_gateway, gateway, gateway->sa_len) == 0) + break; + } + if (rt == NULL) + return (NULL); +#endif /* SMALL_KERNEL */ + rtref(rt); return (rt); @@ -745,33 +753,6 @@ int rtable_mpath_capable(unsigned int rtableid, sa_family_t af) { return (1); -} - -struct rtentry * -rtable_mpath_match(unsigned int rtableid, struct rtentry *rt0, - struct sockaddr *gateway, uint8_t prio) -{ - struct art_node *an = rt0->rt_node; - struct rtentry *rt; - - LIST_FOREACH(rt, &an->an_rtlist, rt_next) { - if (prio != RTP_ANY && - (rt->rt_priority & RTP_MASK) != (prio & RTP_MASK)) - continue; - - if (gateway == NULL) - break; - - if (rt->rt_gateway->sa_len == gateway->sa_len && - memcmp(rt->rt_gateway, gateway, gateway->sa_len) == 0) - break; - } - - if (rt != NULL) - rtref(rt); - rtfree(rt0); - - return (rt); } /* Gateway selection by Hash-Threshold (RFC 2992) */ Index: net/rtable.h =================================================================== RCS file: /cvs/src/sys/net/rtable.h,v retrieving revision 1.8 diff -u -p -r1.8 rtable.h --- net/rtable.h 25 Oct 2015 14:48:51 -0000 1.8 +++ net/rtable.h 26 Oct 2015 19:11:50 -0000 @@ -54,7 +54,7 @@ unsigned int rtable_l2(unsigned int); void rtable_l2set(unsigned int, unsigned int); struct rtentry *rtable_lookup(unsigned int, struct sockaddr *, - struct sockaddr *); + struct sockaddr *, struct sockaddr *, uint8_t); struct rtentry *rtable_match(unsigned int, struct sockaddr *); int rtable_insert(unsigned int, struct sockaddr *, struct sockaddr *, struct sockaddr *, uint8_t, Index: net/rtsock.c =================================================================== RCS file: /cvs/src/sys/net/rtsock.c,v retrieving revision 1.179 diff -u -p -r1.179 rtsock.c --- net/rtsock.c 25 Oct 2015 14:41:09 -0000 1.179 +++ net/rtsock.c 26 Oct 2015 19:11:50 -0000 @@ -620,51 +620,36 @@ route_output(struct mbuf *m, ...) error = EAFNOSUPPORT; goto flush; } + rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK]); - if (rt == NULL) { - error = ESRCH; - goto flush; + info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY], + prio); +#ifdef SMALL_KERNEL + /* + * If we got multipath routes, we require users to specify + * a matching gateway, except for RTM_GET. + */ + if ((rt != NULL) && ISSET(rt->rt_flags, RTF_MPATH) && + (info.rti_info[RTAX_GATEWAY] == NULL) && + (rtm->rtm_type != RTM_GET)) { + rtfree(rt); + rt = NULL; } -#ifndef SMALL_KERNEL - /* First find the right priority. */ - rt = rtable_mpath_match(tableid, rt, NULL, prio); +#endif + /* + * If RTAX_GATEWAY is the argument we're trying to + * change, try to find a compatible route. + */ + if ((rt == NULL) && (info.rti_info[RTAX_GATEWAY] != NULL) && + (rtm->rtm_type == RTM_CHANGE)) { + rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], + info.rti_info[RTAX_NETMASK], NULL, prio); + } + if (rt == NULL) { error = ESRCH; goto flush; } - - - /* - * For RTM_CHANGE/LOCK, if we got multipath routes, - * a matching RTAX_GATEWAY is required. - * OR - * If a gateway is specified then RTM_GET and - * RTM_LOCK must match the gateway no matter - * what even in the non multipath case. - */ - if ((rt->rt_flags & RTF_MPATH) || - (info.rti_info[RTAX_GATEWAY] && rtm->rtm_type != - RTM_CHANGE)) { - rt = rtable_mpath_match(tableid, rt, - info.rti_info[RTAX_GATEWAY], prio); - if (rt == NULL) { - error = ESRCH; - goto flush; - } - /* - * Only RTM_GET may use an empty gateway - * on multipath routes - */ - if (info.rti_info[RTAX_GATEWAY] == NULL && - rtm->rtm_type != RTM_GET) { - rtfree(rt); - rt = NULL; - error = ESRCH; - goto flush; - } - } -#endif /* * RTM_CHANGE/LOCK need a perfect match, rn_lookup()