svn commit: r264986 - head/sys/net

Alexander V. Chernikov melifaro at FreeBSD.org
Sat Apr 26 21:03:42 UTC 2014


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;
 


More information about the svn-src-all mailing list