From owner-svn-src-all@FreeBSD.ORG Sat Apr 26 21:03:42 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 6C357C6F; Sat, 26 Apr 2014 21:03:42 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4B3C51554; Sat, 26 Apr 2014 21:03:42 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s3QL3g31048247; Sat, 26 Apr 2014 21:03:42 GMT (envelope-from melifaro@svn.freebsd.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s3QL3fAX048245; Sat, 26 Apr 2014 21:03:41 GMT (envelope-from melifaro@svn.freebsd.org) Message-Id: <201404262103.s3QL3fAX048245@svn.freebsd.org> From: "Alexander V. Chernikov" Date: Sat, 26 Apr 2014 21:03:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r264986 - head/sys/net X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 26 Apr 2014 21:03:42 -0000 Author: melifaro Date: Sat Apr 26 21:03:41 2014 New Revision: 264986 URL: http://svnweb.freebsd.org/changeset/base/264986 Log: Decouple RTM_CHANGE from RTM_GET handling in rtsock.c:route_output(). RTM_CHANGE is now handled inside route.c:rtrequest1_fib() as it should be. Note change change handler is a separate function rtrequest1_fib_change(). MFC after: 1 month Modified: head/sys/net/route.c head/sys/net/rtsock.c Modified: head/sys/net/route.c ============================================================================== --- head/sys/net/route.c Sat Apr 26 20:27:58 2014 (r264985) +++ head/sys/net/route.c Sat Apr 26 21:03:41 2014 (r264986) @@ -140,6 +140,9 @@ VNET_DEFINE(int, rttrash); /* routes no static VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */ #define V_rtzone VNET(rtzone) +static int rtrequest1_fib_change(struct radix_node_head *, struct rt_addrinfo *, + struct rtentry **, u_int); + /* * handler for net.my_fibnum */ @@ -1408,6 +1411,9 @@ rtrequest1_fib(int req, struct rt_addrin } RT_UNLOCK(rt); break; + case RTM_CHANGE: + error = rtrequest1_fib_change(rnh, info, ret_nrt, fibnum); + break; default: error = EOPNOTSUPP; } @@ -1425,6 +1431,95 @@ bad: #undef ifpaddr #undef flags +#define senderr(e) { error = e; goto bad; } +static int +rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, + struct rtentry **ret_nrt, u_int fibnum) +{ + struct rtentry *rt = NULL; + int error = 0; + int free_ifa = 0; + + rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST], + info->rti_info[RTAX_NETMASK], rnh); + + if (rt == NULL) + return (ESRCH); + +#ifdef RADIX_MPATH + /* + * If we got multipath routes, + * we require users to specify a matching RTAX_GATEWAY. + */ + if (rn_mpath_capable(rnh)) { + rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]); + if (rt == NULL) + return (ESRCH); + } +#endif + + RT_LOCK(rt); + + /* + * New gateway could require new ifaddr, ifp; + * flags may also be different; ifp may be specified + * by ll sockaddr when protocol address is ambiguous + */ + if (((rt->rt_flags & RTF_GATEWAY) && + info->rti_info[RTAX_GATEWAY] != NULL) || + info->rti_info[RTAX_IFP] != NULL || + (info->rti_info[RTAX_IFA] != NULL && + !sa_equal(info->rti_info[RTAX_IFA], rt->rt_ifa->ifa_addr))) { + + error = rt_getifa_fib(info, fibnum); + if (info->rti_ifa != NULL) + free_ifa = 1; + + if (error != 0) + senderr(error); + } + + /* Check if outgoing interface has changed */ + if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa && + rt->rt_ifa != NULL && rt->rt_ifa->ifa_rtrequest != NULL) { + rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, info); + ifa_free(rt->rt_ifa); + } + /* Update gateway address */ + if (info->rti_info[RTAX_GATEWAY] != NULL) { + error = rt_setgate(rt, rt_key(rt), info->rti_info[RTAX_GATEWAY]); + if (error != 0) + senderr(error); + + rt->rt_flags &= ~RTF_GATEWAY; + rt->rt_flags |= (RTF_GATEWAY & info->rti_flags); + } + + if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa) { + ifa_ref(info->rti_ifa); + rt->rt_ifa = info->rti_ifa; + rt->rt_ifp = info->rti_ifp; + } + /* Allow some flags to be toggled on change. */ + rt->rt_flags &= ~RTF_FMASK; + rt->rt_flags |= info->rti_flags & RTF_FMASK; + + if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest != NULL) + rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info); + + if (ret_nrt) { + *ret_nrt = rt; + RT_ADDREF(rt); + } +bad: + RT_UNLOCK(rt); + if (free_ifa != 0) + ifa_free(info->rti_ifa); + return (error); +} +#undef senderr + + int rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) { Modified: head/sys/net/rtsock.c ============================================================================== --- head/sys/net/rtsock.c Sat Apr 26 20:27:58 2014 (r264985) +++ head/sys/net/rtsock.c Sat Apr 26 21:03:41 2014 (r264986) @@ -621,6 +621,7 @@ route_output(struct mbuf *m, struct sock struct rtentry *saved_nrt; case RTM_ADD: + case RTM_CHANGE: if (info.rti_info[RTAX_GATEWAY] == NULL) senderr(EINVAL); saved_nrt = NULL; @@ -635,9 +636,9 @@ route_output(struct mbuf *m, struct sock #endif break; } - error = rtrequest1_fib(RTM_ADD, &info, &saved_nrt, + error = rtrequest1_fib(rtm->rtm_type, &info, &saved_nrt, so->so_fibnum); - if (error == 0 && saved_nrt) { + if (error == 0 && saved_nrt != NULL) { #ifdef INET6 rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; #endif @@ -676,8 +677,6 @@ route_output(struct mbuf *m, struct sock break; case RTM_GET: - case RTM_CHANGE: - case RTM_LOCK: rnh = rt_tables_get_rnh(so->so_fibnum, info.rti_info[RTAX_DST]->sa_family); if (rnh == NULL) @@ -757,133 +756,61 @@ route_output(struct mbuf *m, struct sock RT_ADDREF(rt); RADIX_NODE_HEAD_RUNLOCK(rnh); - switch(rtm->rtm_type) { - - case RTM_GET: - report: - RT_LOCK_ASSERT(rt); - if ((rt->rt_flags & RTF_HOST) == 0 - ? jailed_without_vnet(curthread->td_ucred) - : prison_if(curthread->td_ucred, - rt_key(rt)) != 0) { - RT_UNLOCK(rt); - senderr(ESRCH); - } - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GENMASK] = 0; - if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { - ifp = rt->rt_ifp; - if (ifp) { - info.rti_info[RTAX_IFP] = - ifp->if_addr->ifa_addr; - error = rtm_get_jailed(&info, ifp, rt, - &saun, curthread->td_ucred); - if (error != 0) { - RT_UNLOCK(rt); - senderr(error); - } - if (ifp->if_flags & IFF_POINTOPOINT) - info.rti_info[RTAX_BRD] = - rt->rt_ifa->ifa_dstaddr; - rtm->rtm_index = ifp->if_index; - } else { - info.rti_info[RTAX_IFP] = NULL; - info.rti_info[RTAX_IFA] = NULL; - } - } else if ((ifp = rt->rt_ifp) != NULL) { - rtm->rtm_index = ifp->if_index; - } - len = rt_msg2(rtm->rtm_type, &info, NULL, NULL); - if (len > rtm->rtm_msglen) { - struct rt_msghdr *new_rtm; - R_Malloc(new_rtm, struct rt_msghdr *, len); - if (new_rtm == NULL) { - RT_UNLOCK(rt); - senderr(ENOBUFS); - } - bcopy(rtm, new_rtm, rtm->rtm_msglen); - Free(rtm); rtm = new_rtm; - } - (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL); - if (rt->rt_flags & RTF_GWFLAG_COMPAT) - rtm->rtm_flags = RTF_GATEWAY | - (rt->rt_flags & ~RTF_GWFLAG_COMPAT); - else - rtm->rtm_flags = rt->rt_flags; - rt_getmetrics(rt, &rtm->rtm_rmx); - rtm->rtm_addrs = info.rti_addrs; - break; - - case RTM_CHANGE: - /* - * New gateway could require new ifaddr, ifp; - * flags may also be different; ifp may be specified - * by ll sockaddr when protocol address is ambiguous - */ - if (((rt->rt_flags & RTF_GATEWAY) && - info.rti_info[RTAX_GATEWAY] != NULL) || - info.rti_info[RTAX_IFP] != NULL || - (info.rti_info[RTAX_IFA] != NULL && - !sa_equal(info.rti_info[RTAX_IFA], - rt->rt_ifa->ifa_addr))) { - RT_UNLOCK(rt); - RADIX_NODE_HEAD_LOCK(rnh); - error = rt_getifa_fib(&info, rt->rt_fibnum); - /* - * XXXRW: Really we should release this - * reference later, but this maintains - * historical behavior. - */ - if (info.rti_ifa != NULL) - ifa_free(info.rti_ifa); - RADIX_NODE_HEAD_UNLOCK(rnh); - if (error != 0) - senderr(error); - RT_LOCK(rt); - } - if (info.rti_ifa != NULL && - info.rti_ifa != rt->rt_ifa && - rt->rt_ifa != NULL && - rt->rt_ifa->ifa_rtrequest != NULL) { - rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, - &info); - ifa_free(rt->rt_ifa); - } - if (info.rti_info[RTAX_GATEWAY] != NULL) { - RT_UNLOCK(rt); - RADIX_NODE_HEAD_LOCK(rnh); - RT_LOCK(rt); - - error = rt_setgate(rt, rt_key(rt), - info.rti_info[RTAX_GATEWAY]); - RADIX_NODE_HEAD_UNLOCK(rnh); +report: + RT_LOCK_ASSERT(rt); + if ((rt->rt_flags & RTF_HOST) == 0 + ? jailed_without_vnet(curthread->td_ucred) + : prison_if(curthread->td_ucred, + rt_key(rt)) != 0) { + RT_UNLOCK(rt); + senderr(ESRCH); + } + info.rti_info[RTAX_DST] = rt_key(rt); + info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; + info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_GENMASK] = 0; + if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { + ifp = rt->rt_ifp; + if (ifp) { + info.rti_info[RTAX_IFP] = + ifp->if_addr->ifa_addr; + error = rtm_get_jailed(&info, ifp, rt, + &saun, curthread->td_ucred); if (error != 0) { RT_UNLOCK(rt); senderr(error); } - rt->rt_flags &= ~RTF_GATEWAY; - rt->rt_flags |= (RTF_GATEWAY & info.rti_flags); + if (ifp->if_flags & IFF_POINTOPOINT) + info.rti_info[RTAX_BRD] = + rt->rt_ifa->ifa_dstaddr; + rtm->rtm_index = ifp->if_index; + } else { + info.rti_info[RTAX_IFP] = NULL; + info.rti_info[RTAX_IFA] = NULL; } - if (info.rti_ifa != NULL && - info.rti_ifa != rt->rt_ifa) { - ifa_ref(info.rti_ifa); - rt->rt_ifa = info.rti_ifa; - rt->rt_ifp = info.rti_ifp; + } else if ((ifp = rt->rt_ifp) != NULL) { + rtm->rtm_index = ifp->if_index; + } + len = rt_msg2(rtm->rtm_type, &info, NULL, NULL); + if (len > rtm->rtm_msglen) { + struct rt_msghdr *new_rtm; + R_Malloc(new_rtm, struct rt_msghdr *, len); + if (new_rtm == NULL) { + RT_UNLOCK(rt); + senderr(ENOBUFS); } - /* Allow some flags to be toggled on change. */ - rt->rt_flags = (rt->rt_flags & ~RTF_FMASK) | - (rtm->rtm_flags & RTF_FMASK); - rt_setmetrics(rtm, rt); - rtm->rtm_index = rt->rt_ifp->if_index; - if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) - rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); - /* FALLTHROUGH */ - case RTM_LOCK: - /* We don't support locks anymore */ - break; + bcopy(rtm, new_rtm, rtm->rtm_msglen); + Free(rtm); rtm = new_rtm; } + (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL); + if (rt->rt_flags & RTF_GWFLAG_COMPAT) + rtm->rtm_flags = RTF_GATEWAY | + (rt->rt_flags & ~RTF_GWFLAG_COMPAT); + else + rtm->rtm_flags = rt->rt_flags; + rt_getmetrics(rt, &rtm->rtm_rmx); + rtm->rtm_addrs = info.rti_addrs; + RT_UNLOCK(rt); break;