Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Oct 2011 01:40:21 +0400
From:      Sergey Kandaurov <pluknet@gmail.com>
To:        Devin Teske <devin.teske@fisglobal.com>
Cc:        Dave Robison <Dave.Robison@fisglobal.com>, FreeBSD amd64 <freebsd-amd64@freebsd.org>
Subject:   Re: 32-bit route(8) on amd64 host and jails
Message-ID:  <CAE-mSO%2B_hc%2BGJHYUyX6dBS6NckV=iiHRrGMYbc=AxQeqKwK2Zg@mail.gmail.com>
In-Reply-To: <CAE-mSO%2B4KKWeC6-Z3UAi70bxxEUJL5gUD0phEfNzzkDMXrA3pg@mail.gmail.com>
References:  <714EF3C9-33B0-4EF5-B52C-1E95F7F432F9@fisglobal.com> <CAE-mSO%2B4KKWeC6-Z3UAi70bxxEUJL5gUD0phEfNzzkDMXrA3pg@mail.gmail.com>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]
On 21 September 2011 16:47, Sergey Kandaurov <pluknet@gmail.com> wrote:
> On 21 September 2011 06:40, Devin Teske <devin.teske@fisglobal.com> wrote:
>> I'm noticing that a 32-bit route(8) shows strange behaviour while running under an amd64 kernel (regardless of whether in the base-host -- utilizing /usr/lib32/libc.so.7 -- or in a jail and/or vimage -- 32-bit in nature; results are same).
>>
>> Executable runs fine, but you can't (a) set the default route or (b) view the default route (after successfully setting it with the amd64 build, of course).
>>
>> ASIDE: This is under 8.1-RELEASE.
>>
>> When attempting to set the default route, you get the following...
>>
>> root@kps0a / # route add -net default 10.10.125.99
>> route: writing to routing socket: Invalid argument
>> add net default: gateway 10.10.125.99: Invalid argument
>>
>> Meanwhile, using the amd64 version, no issues.
>>
>> When attempting to view the default route, you get the following...
>>
>> root@kps0a / # route -n get default
>>   route to: default
>> destination: default
>>       mask: default
>>    gateway: default
>>      flags: <UP,GATEWAY,DONE,STATIC>
>>  recvpipe  sendpipe  ssthresh  rtt,msec    mtu        weight    expire
>>       0         0         0         0         0         0  -1316570637
>>
>> It's the "gateway: default" that's out of place.
>>
>
> Currently, FreeBSD has a poor shape of rtsocket freebsd32 compatibility,
> AFAIK only sysctl layer (sysctl_rtsock) is aware of it.
> That means when a 32bit app writes some data to a routing socket,
> kernel expects to receive it in the native ABI, and it doesn't work.

Can you please try this preliminary patch and report back?
You only need to rebuild kernel and reboot with the attached patch
to enable use of e.g. 32-bit route(8) command on amd64 kernel.
No any userland utility needs to rebuild to enable the compatibility.
Tested on 8.2 amd64 only with route get default and route delete/add.

-- 
wbr,
pluknet

[-- Attachment #2 --]
Index: sys/net/rtsock.c
===================================================================
--- sys/net/rtsock.c	(revision 225671)
+++ sys/net/rtsock.c	(working copy)
@@ -75,6 +75,7 @@ extern void sctp_addr_change(struct ifaddr *ifa, i
 
 #ifdef COMPAT_FREEBSD32
 #include <sys/mount.h>
+#include <sys/sysent.h>
 #include <compat/freebsd32/freebsd32.h>
 
 struct if_data32 {
@@ -114,6 +115,42 @@ struct if_msghdr32 {
 	uint16_t ifm_index;
 	struct	if_data32 ifm_data;
 };
+
+struct rt_metrics32 {
+	uint32_t	rmx_locks;
+	uint32_t	rmx_mtu;
+	uint32_t	rmx_hopcount;
+	uint32_t	rmx_expire;
+	uint32_t	rmx_recvpipe;
+	uint32_t	rmx_sendpipe;
+	uint32_t	rmx_ssthresh;
+	uint32_t	rmx_rtt;
+	uint32_t	rmx_rttvar;
+	uint32_t	rmx_pksent;
+	uint32_t	rmx_weight;
+	uint32_t	rmx_filler[3];
+};
+
+struct rt_msghdr32 {
+	uint16_t	rtm_msglen;
+	uint8_t		rtm_version;
+	uint8_t		rtm_type;
+	uint16_t	rtm_index;
+	uint16_t	rtm_hole1;
+	uint32_t	rtm_flags;
+	uint32_t	rtm_addrs;
+	uint32_t	rtm_pid;
+	uint32_t	rtm_seq;
+	uint32_t	rtm_errno;
+	uint32_t	rtm_fmask;
+	uint32_t	rtm_inits;
+	struct rt_metrics32 rtm_rmx;
+};
+
+#define	SA_SIZE32(sa)						\
+    (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?	\
+	sizeof(int32_t)		:				\
+	1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(int32_t) - 1)))
 #endif
 
 MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
@@ -501,6 +538,138 @@ rtm_get_jailed(struct rt_addrinfo *info, struct if
 	return (0);
 }
 
+#ifdef COMPAT_FREEBSD32
+static void
+freebsd32_rt_metrics_in(struct rt_metrics32 *src, struct rt_metrics *dst)
+{
+
+	bzero(dst, sizeof(*dst));
+	CP(*src, *dst, rmx_mtu);
+	CP(*src, *dst, rmx_expire);
+	CP(*src, *dst, rmx_pksent);
+	CP(*src, *dst, rmx_weight);
+}
+
+static void
+freebsd32_rt_metrics_out(struct rt_metrics *src, struct rt_metrics32 *dst)
+{
+
+	bzero(dst, sizeof(*dst));
+	CP(*src, *dst, rmx_mtu);
+	CP(*src, *dst, rmx_expire);
+	CP(*src, *dst, rmx_pksent);
+	CP(*src, *dst, rmx_weight);
+}
+
+static void
+freebsd32_rt_msghdr_in(struct rt_msghdr32 *src, struct rt_msghdr *dst)
+{
+
+	bzero(dst, sizeof(*dst));
+	/* CP(*src, *dst, rtm_msglen); */	/* updated separately */
+	CP(*src, *dst, rtm_version);
+	CP(*src, *dst, rtm_type);
+	CP(*src, *dst, rtm_index);
+	CP(*src, *dst, rtm_flags);
+	CP(*src, *dst, rtm_addrs);
+	CP(*src, *dst, rtm_pid);
+	CP(*src, *dst, rtm_seq);
+	CP(*src, *dst, rtm_errno);
+	CP(*src, *dst, rtm_fmask);
+	CP(*src, *dst, rtm_inits);
+	freebsd32_rt_metrics_in(&src->rtm_rmx, &dst->rtm_rmx);
+}
+
+static void
+freebsd32_rt_msghdr_out(struct rt_msghdr *src, struct rt_msghdr32 *dst)
+{
+
+	bzero(dst, sizeof(*dst));
+	/* CP(*src, *dst, rtm_msglen); */	/* updated separately */
+	CP(*src, *dst, rtm_version);
+	CP(*src, *dst, rtm_type);
+	CP(*src, *dst, rtm_index);
+	CP(*src, *dst, rtm_flags);
+	CP(*src, *dst, rtm_addrs);
+	CP(*src, *dst, rtm_pid);
+	CP(*src, *dst, rtm_seq);
+	CP(*src, *dst, rtm_errno);
+	CP(*src, *dst, rtm_fmask);
+	CP(*src, *dst, rtm_inits);
+	freebsd32_rt_metrics_out(&src->rtm_rmx, &dst->rtm_rmx);
+}
+
+static int
+freebsd32_rt_mspace_len_in(caddr_t cp, caddr_t cplim, int *buflen)
+{
+	struct sockaddr *sa;
+	int i;
+
+	for (i = 0, *buflen = 0; i < RTAX_MAX && cp < cplim; i++) {
+		sa = (struct sockaddr *)cp;
+
+		if (cp + sa->sa_len > cplim)
+			return (EINVAL);
+		cp += SA_SIZE32(sa);
+		*buflen += SA_SIZE(sa);
+	}
+	return (0);
+}
+
+static int
+freebsd32_rt_mspace_len_out(caddr_t cp, caddr_t cplim, int *buflen)
+{
+	struct sockaddr *sa;
+	int i;
+
+	for (i = 0, *buflen = 0; i < RTAX_MAX && cp < cplim; i++) {
+		sa = (struct sockaddr *)cp;
+
+		if (cp + sa->sa_len > cplim)
+			return (EINVAL);
+		cp += SA_SIZE(sa);
+		*buflen += SA_SIZE32(sa);
+	}
+	return (0);
+}
+
+static int
+freebsd32_rt_mspace_in(caddr_t cp, caddr_t cp64, caddr_t cplim)
+{
+	struct sockaddr *sa;
+	int i;
+
+	for (i = 0; i < RTAX_MAX && cp < cplim; i++) {
+		sa = (struct sockaddr *)cp;
+
+		if (cp + sa->sa_len > cplim)
+			return (EINVAL);
+		memcpy(cp64, cp, SA_SIZE32(sa));
+		cp += SA_SIZE32(sa);
+		cp64 += SA_SIZE(sa);
+	}
+	return (0);
+}
+
+static int
+freebsd32_rt_mspace_out(caddr_t cp, caddr_t cp32, caddr_t cplim)
+{
+	struct sockaddr *sa;
+	int i;
+
+	for (i = 0; i < RTAX_MAX && cp < cplim; i++) {
+		sa = (struct sockaddr *)cp;
+
+		if (cp + sa->sa_len > cplim)
+			return (EINVAL);
+		memcpy(cp32, cp, SA_SIZE(sa));
+		cp += SA_SIZE(sa);
+		cp32 += SA_SIZE32(sa);
+	}
+	return (0);
+}
+#endif
+
 /*ARGSUSED*/
 static int
 route_output(struct mbuf *m, struct socket *so)
@@ -513,7 +682,14 @@ route_output(struct mbuf *m, struct socket *so)
 	int len, error = 0;
 	struct ifnet *ifp = NULL;
 	union sockaddr_union saun;
+	size_t rtmlen;
+#ifdef COMPAT_FREEBSD32
+	struct rt_msghdr32 *rtm32 = NULL;
+	int len32 = 0, rt_mspace_len = 0, wrap32 = 0;
 
+	if (SV_CURPROC_FLAG(SV_ILP32))
+		wrap32 = 1;
+#endif
 #define senderr(e) { error = e; goto flush;}
 	if (m == NULL || ((m->m_len < sizeof(long)) &&
 		       (m = m_pullup(m, sizeof(long))) == NULL))
@@ -521,17 +697,50 @@ route_output(struct mbuf *m, struct socket *so)
 	if ((m->m_flags & M_PKTHDR) == 0)
 		panic("route_output");
 	len = m->m_pkthdr.len;
-	if (len < sizeof(*rtm) ||
+
+#ifdef COMPAT_FREEBSD32
+	if (wrap32) {
+		rtmlen = sizeof(*rtm32);
+		len32 = len;
+	} else
+#endif
+		rtmlen = sizeof(*rtm);
+
+	if (len < rtmlen ||
 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
 		info.rti_info[RTAX_DST] = NULL;
 		senderr(EINVAL);
 	}
-	R_Malloc(rtm, struct rt_msghdr *, len);
+
+#ifdef COMPAT_FREEBSD32
+	if (wrap32) {
+		R_Malloc(rtm32, struct rt_msghdr32 *, len32);
+		if (rtm32 == NULL) {
+			info.rti_info[RTAX_DST] = NULL;
+			senderr(ENOBUFS);
+		}
+		m_copydata(m, 0, len32, (caddr_t)rtm32);
+		freebsd32_rt_mspace_len_in((caddr_t)(rtm32 + 1), len32 + (caddr_t)rtm32, &rt_mspace_len);
+		/* fixup len to alloc rtm of native size */
+		len = rt_mspace_len + sizeof(*rtm);
+	}
+#endif
+	R_Zalloc(rtm, struct rt_msghdr *, len);
 	if (rtm == NULL) {
 		info.rti_info[RTAX_DST] = NULL;
 		senderr(ENOBUFS);
 	}
-	m_copydata(m, 0, len, (caddr_t)rtm);
+
+#ifdef COMPAT_FREEBSD32
+	if (wrap32) {
+		freebsd32_rt_msghdr_in(rtm32, rtm);
+		freebsd32_rt_mspace_in((caddr_t)(rtm32 + 1),
+		    (caddr_t)(rtm + 1), (caddr_t)rtm32 + len32);
+		rtm->rtm_msglen = len;
+	} else
+#endif
+		m_copydata(m, 0, len, (caddr_t)rtm);
+
 	if (rtm->rtm_version != RTM_VERSION) {
 		info.rti_info[RTAX_DST] = NULL;
 		senderr(EPROTONOSUPPORT);
@@ -543,6 +752,16 @@ route_output(struct mbuf *m, struct socket *so)
 		info.rti_info[RTAX_DST] = NULL;
 		senderr(EINVAL);
 	}
+/*
+        int i; uint16_t *j;
+
+        for (i = 0; i * (int)sizeof(uint16_t) < len; i++) {
+                  j = (uint16_t *)rtm;
+                  if (i % 8 == 0)
+                         printf("\n0x%04jx ", (uintmax_t)i*sizeof(uint16_t));
+                  printf("%04x ", bswap16(j[i]));
+        }; printf("\n");
+*/
 	info.rti_flags = rtm->rtm_flags;
 	if (info.rti_info[RTAX_DST] == NULL ||
 	    info.rti_info[RTAX_DST]->sa_family >= AF_MAX ||
@@ -877,12 +1096,41 @@ flush:
 		rp = sotorawcb(so);
 	}
 	if (rtm) {
-		m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
-		if (m->m_pkthdr.len < rtm->rtm_msglen) {
-			m_freem(m);
-			m = NULL;
-		} else if (m->m_pkthdr.len > rtm->rtm_msglen)
-			m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
+#ifdef COMPAT_FREEBSD32
+		if (wrap32) {
+			int rt_mspace_len32;
+
+			freebsd32_rt_mspace_len_out((caddr_t)(rtm + 1),
+			    len + (caddr_t)rtm, &rt_mspace_len32);
+			len32 = rt_mspace_len32 + sizeof(*rtm32);
+			if (len32 > rtm32->rtm_msglen) {
+				struct rt_msghdr32 *new_rtm32;
+				R_Malloc(new_rtm32, struct rt_msghdr32 *, len32);
+				if (new_rtm32 == NULL)
+					senderr(ENOBUFS);
+				bcopy(rtm32, new_rtm32, rtm32->rtm_msglen);
+				Free(rtm32); rtm32 = new_rtm32;
+			}
+			freebsd32_rt_msghdr_out(rtm, rtm32);
+			rtm32->rtm_msglen = len32;
+			freebsd32_rt_mspace_out((caddr_t)(rtm + 1),
+			    (caddr_t)(rtm32 + 1), (caddr_t)rtm + len);
+
+			m_copyback(m, 0, rtm32->rtm_msglen, (caddr_t)rtm32);
+			if (m->m_pkthdr.len < rtm32->rtm_msglen) {
+				m_freem(m);
+				m = NULL;
+			} else if (m->m_pkthdr.len > rtm32->rtm_msglen)
+				m_adj(m, rtm32->rtm_msglen - m->m_pkthdr.len);
+		} else {
+#endif
+			m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
+			if (m->m_pkthdr.len < rtm->rtm_msglen) {
+				m_freem(m);
+				m = NULL;
+			} else if (m->m_pkthdr.len > rtm->rtm_msglen)
+				m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
+		}
 	}
 	if (m) {
 		if (rp) {
@@ -898,8 +1146,13 @@ flush:
 			rt_dispatch(m, info.rti_info[RTAX_DST]);
 	}
 	/* info.rti_info[RTAX_DST] (used above) can point inside of rtm */
-	if (rtm)
+	if (rtm) {
 		Free(rtm);
+#ifdef COMPAT_FREEBSD32
+		if (wrap32)
+			Free(rtm32);
+#endif
+	}
     }
 	return (error);
 #undef	sa_equal
home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAE-mSO%2B_hc%2BGJHYUyX6dBS6NckV=iiHRrGMYbc=AxQeqKwK2Zg>