Add proof-of-concept code for enabling system calls to rump virtual

kernels running in other processes on the same machine or on an
entirely different host.  I wrote this a while ago and am now
committing it mainly to avoid losing it.  It works, but could do
with a little tuning here and there.

What this will hopefully eventually buy us is the ability to use
standard userland tools to configure rump kernels, e.g. ifconfig(8)
and route(8) could be used to configure the networking stack provided
by a rump kernel.  Also some distributed OS implications may apply.

fun fact: a system call which just does copyin/copyout takes >1000x
longer when made over the LAN as compared to when made on the same
machine.
This commit is contained in:
pooka 2009-04-29 17:51:47 +00:00
parent c51cd914ad
commit a22ec3808b
10 changed files with 861 additions and 16 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rump.h,v 1.12 2009/03/27 13:47:53 pooka Exp $ */
/* $NetBSD: rump.h,v 1.13 2009/04/29 18:00:49 pooka Exp $ */
/*
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
@ -127,6 +127,7 @@ int rump_vfs_fhtovp(struct mount *, struct fid *, struct vnode **);
int rump_vfs_vptofh(struct vnode *, struct fid *, size_t *);
void rump_vfs_syncwait(struct mount *);
struct lwp *rump_newproc_switch(void);
struct lwp *rump_setup_curlwp(pid_t, lwpid_t, int);
struct lwp *rump_get_curlwp(void);
void rump_clear_curlwp(void);
@ -141,6 +142,8 @@ int rump_virtif_create(int);
typedef int (*rump_sysproxy_t)(int, void *, uint8_t *, size_t, register_t *);
int rump_sysproxy_set(rump_sysproxy_t, void *);
int rump_sysproxy_socket_setup_client(int);
int rump_sysproxy_socket_setup_server(int);
/*
* Begin rump syscall conditionals. Yes, something a little better

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile.rumpkern,v 1.43 2009/04/16 14:07:17 pooka Exp $
# $NetBSD: Makefile.rumpkern,v 1.44 2009/04/29 17:51:47 pooka Exp $
#
.include "${RUMPTOP}/Makefile.rump"
@ -14,7 +14,8 @@ LIB= rump
#
# Source modules, first the ones specifically implemented for librump.
#
SRCS= rump.c emul.c intr.c locks.c ltsleep.c percpu.c pool.c sleepq.c vm.c
SRCS= rump.c emul.c intr.c locks.c ltsleep.c percpu.c pool.c \
sleepq.c sysproxy_socket.c vm.c
# stubs
#

View File

@ -1,4 +1,4 @@
/* $NetBSD: emul.c,v 1.87 2009/04/26 20:41:24 pooka Exp $ */
/* $NetBSD: emul.c,v 1.88 2009/04/29 17:51:47 pooka Exp $ */
/*
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: emul.c,v 1.87 2009/04/26 20:41:24 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: emul.c,v 1.88 2009/04/29 17:51:47 pooka Exp $");
#include <sys/param.h>
#include <sys/malloc.h>
@ -125,7 +125,10 @@ int
copyin(const void *uaddr, void *kaddr, size_t len)
{
memcpy(kaddr, uaddr, len);
if (curproc->p_vmspace == &rump_vmspace)
memcpy(kaddr, uaddr, len);
else
rump_sysproxy_copyin(uaddr, kaddr, len);
return 0;
}
@ -133,7 +136,10 @@ int
copyout(const void *kaddr, void *uaddr, size_t len)
{
memcpy(uaddr, kaddr, len);
if (curproc->p_vmspace == &rump_vmspace)
memcpy(uaddr, kaddr, len);
else
rump_sysproxy_copyout(kaddr, uaddr, len);
return 0;
}
@ -148,7 +154,10 @@ int
copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
{
strlcpy(kaddr, uaddr, len);
if (curproc->p_vmspace == &rump_vmspace)
strlcpy(kaddr, uaddr, len);
else
rump_sysproxy_copyin(uaddr, kaddr, len);
if (done)
*done = strlen(kaddr)+1; /* includes termination */
return 0;
@ -158,7 +167,10 @@ int
copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done)
{
strlcpy(uaddr, kaddr, len);
if (curproc->p_vmspace == &rump_vmspace)
strlcpy(uaddr, kaddr, len);
else
rump_sysproxy_copyout(kaddr, uaddr, len);
if (done)
*done = strlen(uaddr)+1; /* includes termination */
return 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: rump.c,v 1.103 2009/04/29 15:49:28 pooka Exp $ */
/* $NetBSD: rump.c,v 1.104 2009/04/29 17:51:47 pooka Exp $ */
/*
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.103 2009/04/29 15:49:28 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.104 2009/04/29 17:51:47 pooka Exp $");
#include <sys/param.h>
#include <sys/atomic.h>
@ -303,6 +303,25 @@ rump_uio_free(struct uio *uio)
return resid;
}
/* public interface */
static pid_t nextpid = 1;
struct lwp *
rump_newproc_switch()
{
struct lwp *oldlwp = curlwp;
pid_t mypid;
mypid = atomic_inc_uint_nv(&nextpid);
if (__predict_false(mypid == 0))
mypid = atomic_inc_uint_nv(&nextpid);
rumpuser_set_curlwp(NULL);
rump_setup_curlwp(mypid, 0, 1);
return oldlwp;
}
/* rump private */
struct lwp *
rump_setup_curlwp(pid_t pid, lwpid_t lid, int set)
{
@ -335,17 +354,28 @@ rump_setup_curlwp(pid_t pid, lwpid_t lid, int set)
return l;
}
/* rump private. NEEDS WORK! */
void
rump_set_vmspace(struct vmspace *vm)
{
struct proc *p = curproc;
p->p_vmspace = vm;
}
void
rump_clear_curlwp(void)
{
struct lwp *l;
struct proc *p;
l = rumpuser_get_curlwp();
if (l->l_proc->p_pid != 0) {
p = l->l_proc;
if (p->p_pid != 0) {
fd_free();
rump_proc_vfs_release(l->l_proc);
rump_proc_vfs_release(p);
rump_cred_destroy(l->l_cred);
kmem_free(l->l_proc, sizeof(*l->l_proc));
kmem_free(p, sizeof(*p));
}
kmem_free(l, sizeof(*l));
rumpuser_set_curlwp(NULL);

View File

@ -1,4 +1,4 @@
/* $NetBSD: rump_private.h,v 1.27 2009/04/26 20:41:24 pooka Exp $ */
/* $NetBSD: rump_private.h,v 1.28 2009/04/29 17:51:47 pooka Exp $ */
/*
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
@ -31,6 +31,7 @@
#define _SYS_RUMP_PRIVATE_H_
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lwp.h>
#include <sys/proc.h>
#include <sys/systm.h>
@ -54,6 +55,8 @@ extern struct rumpuser_mtx *rump_giantlock;
extern int rump_threads;
extern struct sysent rump_sysent[];
void rumpvm_init(void);
void rump_sleepers_init(void);
struct vm_page *rumpvm_makepage(struct uvm_object *, voff_t);
@ -65,6 +68,7 @@ void rump_gettime(struct timespec *);
void rump_getuptime(struct timespec *);
lwpid_t rump_nextlid(void);
void rump_set_vmspace(struct vmspace *);
typedef void (*rump_proc_vfs_init_fn)(struct proc *);
typedef void (*rump_proc_vfs_release_fn)(struct proc *);
@ -73,8 +77,10 @@ rump_proc_vfs_release_fn rump_proc_vfs_release;
extern struct cpu_info rump_cpu;
extern struct sysent rump_sysent[];
extern rump_sysproxy_t rump_sysproxy;
extern void *rump_sysproxy_arg;
int rump_sysproxy_copyout(const void *, void *, size_t);
int rump_sysproxy_copyin(const void *, void *, size_t);
#endif /* _SYS_RUMP_PRIVATE_H_ */

View File

@ -0,0 +1,614 @@
/* $NetBSD: sysproxy_socket.c,v 1.1 2009/04/29 17:51:47 pooka Exp $ */
/*
* Copyright (c) 2009 Antti Kantee. All Rights Reserved.
*
* Development of this software was supported by The Nokia Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sysproxy_socket.c,v 1.1 2009/04/29 17:51:47 pooka Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/kthread.h>
#include <sys/queue.h>
#include <sys/syscall.h>
#include <rump/rump.h>
#include <rump/rumpuser.h>
#include "rump_private.h"
/*
* This is a very simple RPC mechanism. It defines:
*
* 1) system call
* 2) copyin
* 3) copyout
*
* Currently all the data is in host format, so this can't really be
* used to make cross-site calls. Extending to something like XMLRPC
* is possible, but takes some amount of programming effort, since all
* the kernel data structures and types are defined in C.
*
* XXX: yes, this is overall implemented in a very lazy fashion
* currently. Hopefully it will get better. And hopefully the
* global "sock" will go away, it's quite disgusting.
*/
enum rumprpc { RUMPRPC_SYSCALL, RUMPRPC_SYSCALL_RESP,
RUMPRPC_COPYIN, RUMPRPC_COPYIN_RESP,
RUMPRPC_COPYOUT, RUMPRPC_COPYOUT_RESP };
struct rumprpc_head {
uint64_t rpch_flen;
uint32_t rpch_reqno;
int rpch_type;
};
struct rumprpc_sysreq {
struct rumprpc_head rpc_head;
int rpc_sysnum;
uint8_t rpc_data[0];
};
struct rumprpc_sysresp {
struct rumprpc_head rpc_head;
int rpc_error;
register_t rpc_retval;
};
struct rumprpc_copydata {
struct rumprpc_head rpc_head;
void *rpc_addr;
size_t rpc_len;
uint8_t rpc_data[0];
};
struct sysproxy_qent {
uint32_t reqno;
struct rumprpc_head *rpch_resp;
kcondvar_t cv;
TAILQ_ENTRY(sysproxy_qent) entries;
};
static TAILQ_HEAD(, sysproxy_qent) sendq = TAILQ_HEAD_INITIALIZER(sendq);
static TAILQ_HEAD(, sysproxy_qent) recvq = TAILQ_HEAD_INITIALIZER(recvq);
static bool sendavail = true;
static kmutex_t sendmtx, recvmtx;
static unsigned reqno;
static struct sysproxy_qent *
get_qent(void)
{
struct sysproxy_qent *qent;
unsigned myreq = atomic_inc_uint_nv(&reqno);
qent = kmem_alloc(sizeof(*qent), KM_SLEEP);
qent->reqno = myreq;
qent->rpch_resp = NULL;
cv_init(&qent->cv, "sproxyq");
return qent;
}
static void
put_qent(struct sysproxy_qent *qent)
{
cv_destroy(&qent->cv);
kmem_free(qent, sizeof(*qent));
}
static int
write_n(int s, uint8_t *data, size_t dlen)
{
ssize_t n;
size_t done;
int error;
error = 0;
for (done = 0; done < dlen; done += n) {
n = rumpuser_write(s, data + done, dlen - done, &error);
if (n <= 0) {
if (n == -1)
return error;
return ECONNRESET;
}
}
return error;
}
static int
read_n(int s, uint8_t *data, size_t dlen)
{
ssize_t n;
size_t done;
int error;
error = 0;
for (done = 0; done < dlen; done += n) {
n = rumpuser_read(s, data + done, dlen - done, &error);
if (n <= 0) {
if (n == -1)
return error;
return ECONNRESET;
}
}
return error;
}
static void
dosend(int s, struct sysproxy_qent *qent, uint8_t *data, size_t len, bool rq)
{
int error;
/*
* Send. If the sendq is empty, we send in current thread context.
* Otherwise we enqueue ourselves and block until we are able to
* send in current thread context, i.e. we are the first in the queue.
*/
mutex_enter(&sendmtx);
if (!sendavail) {
TAILQ_INSERT_TAIL(&sendq, qent, entries);
while (qent != TAILQ_FIRST(&sendq))
cv_wait(&qent->cv, &sendmtx);
KASSERT(qent == TAILQ_FIRST(&sendq));
TAILQ_REMOVE(&sendq, qent, entries);
}
sendavail = false;
mutex_exit(&sendmtx);
/*
* Put ourselves onto the receive queue already now in case
* the response arrives "immediately" after sending.
*/
if (rq) {
mutex_enter(&recvmtx);
TAILQ_INSERT_TAIL(&recvq, qent, entries);
mutex_exit(&recvmtx);
}
/* XXX: need better error recovery */
if ((error = write_n(s, data, len)) != 0)
panic("unrecoverable error %d (sloppy)", error);
}
struct wrk {
void (*wfn)(void *arg);
void *arg;
kcondvar_t wrkcv;
LIST_ENTRY(wrk) entries;
};
static LIST_HEAD(, wrk) idlewrker = LIST_HEAD_INITIALIZER(idlewrker);
#define NIDLE_MAX 5
static kmutex_t wrkmtx;
static unsigned nwrk, nidle;
/*
* workers for handling requests. comes with simple little pooling
* for threads.
*/
static void
wrkthread(void *arg)
{
struct wrk *wrk = arg;
mutex_enter(&wrkmtx);
nidle++;
for (;;) {
while (wrk->wfn == NULL)
cv_wait(&wrk->wrkcv, &wrkmtx);
nidle--;
mutex_exit(&wrkmtx);
wrk->wfn(wrk->arg);
wrk->wfn = NULL;
wrk->arg = NULL;
mutex_enter(&wrkmtx);
if (++nidle > NIDLE_MAX) {
nidle--;
break;
}
LIST_INSERT_HEAD(&idlewrker, wrk, entries);
}
nwrk--;
mutex_exit(&wrkmtx);
cv_destroy(&wrk->wrkcv);
kmem_free(wrk, sizeof(*wrk));
kthread_exit(0);
}
/*
* Enqueue work into a separate thread context. Will create a new
* thread if there are none available.
*/
static void
wrkenqueue(void (*wfn)(void *), void *arg)
{
struct wrk *wrk;
int error;
mutex_enter(&wrkmtx);
if (nidle == 0) {
nwrk++;
if (nwrk > 30)
printf("syscall proxy warning: over 30 workers\n");
mutex_exit(&wrkmtx);
wrk = kmem_zalloc(sizeof(*wrk), KM_SLEEP);
cv_init(&wrk->wrkcv, "sproxywrk");
retry:
error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
wrkthread, wrk, NULL, "spw_%d", nwrk);
if (error) {
printf("kthread_create failed: %d. retry.\n", error);
kpause("eagain", false, hz, NULL);
goto retry;
}
} else {
wrk = LIST_FIRST(&idlewrker);
LIST_REMOVE(wrk, entries);
mutex_exit(&wrkmtx);
}
wrk->wfn = wfn;
wrk->arg = arg;
mutex_enter(&wrkmtx);
cv_signal(&wrk->wrkcv);
mutex_exit(&wrkmtx);
}
static int sock; /* XXXXXX */
int
rump_sysproxy_copyout(const void *kaddr, void *uaddr, size_t len)
{
struct rumprpc_copydata *req;
struct sysproxy_qent *qent = get_qent();
size_t totlen = sizeof(*req) + len;
req = kmem_alloc(totlen, KM_SLEEP);
req->rpc_head.rpch_flen = totlen;
req->rpc_head.rpch_reqno = qent->reqno;
req->rpc_head.rpch_type = RUMPRPC_COPYOUT;
req->rpc_addr = uaddr;
req->rpc_len = len;
memcpy(req->rpc_data, kaddr, len);
/* XXX: handle async? */
dosend(sock, qent, (uint8_t *)req, totlen, false);
kmem_free(req, totlen);
put_qent(qent);
return 0;
}
int
rump_sysproxy_copyin(const void *uaddr, void *kaddr, size_t len)
{
struct sysproxy_qent *qent = get_qent();
struct rumprpc_copydata req, *resp;
/* build request */
req.rpc_head.rpch_flen = sizeof(req);
req.rpc_head.rpch_reqno = qent->reqno;
req.rpc_head.rpch_type = RUMPRPC_COPYIN;
req.rpc_addr = __UNCONST(uaddr);
req.rpc_len = len;
dosend(sock, qent, (uint8_t *)&req, sizeof(req), true);
/*
* Wake up next sender or just toggle availability
*/
mutex_enter(&sendmtx);
if (TAILQ_EMPTY(&sendq)) {
sendavail = true;
} else {
cv_signal(&TAILQ_FIRST(&sendq)->cv);
}
mutex_exit(&sendmtx);
/* Wait for response */
mutex_enter(&recvmtx);
while (qent->rpch_resp == NULL)
cv_wait(&qent->cv, &recvmtx);
mutex_exit(&recvmtx);
resp = (struct rumprpc_copydata *)qent->rpch_resp;
/* we trust our kernel */
KASSERT(resp->rpc_head.rpch_type == RUMPRPC_COPYIN_RESP);
memcpy(kaddr, resp->rpc_data, len);
kmem_free(resp, resp->rpc_head.rpch_flen);
put_qent(qent);
return 0;
}
struct vmspace rump_sysproxy_vmspace;
static void
handle_syscall(void *arg)
{
struct rumprpc_sysreq *req = arg;
struct sysproxy_qent *qent = get_qent();
struct rumprpc_sysresp resp;
struct sysent *callp;
struct lwp *mylwp, *l;
resp.rpc_head.rpch_flen = sizeof(resp);
resp.rpc_head.rpch_reqno = req->rpc_head.rpch_reqno;
resp.rpc_head.rpch_type = RUMPRPC_SYSCALL_RESP;
if (__predict_false(req->rpc_sysnum >= SYS_NSYSENT)) {
resp.rpc_error = ENOSYS;
dosend(sock, qent, (uint8_t *)&resp, sizeof(resp), false);
kmem_free(req, req->rpc_head.rpch_flen);
put_qent(qent);
return;
}
callp = rump_sysent + req->rpc_sysnum;
mylwp = rump_newproc_switch();
rump_set_vmspace(&rump_sysproxy_vmspace);
l = curlwp;
resp.rpc_retval = 0; /* default */
resp.rpc_error = callp->sy_call(l, (void *)req->rpc_data,
&resp.rpc_retval);
rump_clear_curlwp();
rumpuser_set_curlwp(mylwp);
kmem_free(req, req->rpc_head.rpch_flen);
dosend(sock, qent, (uint8_t *)&resp, sizeof(resp), false);
put_qent(qent);
}
static void
handle_copyin(void *arg)
{
struct rumprpc_copydata *req = arg;
struct sysproxy_qent *qent = get_qent();
struct rumprpc_copydata *resp;
size_t totlen = sizeof(*resp) + req->rpc_len;
resp = kmem_alloc(totlen, KM_SLEEP);
resp->rpc_head.rpch_flen = totlen;
resp->rpc_head.rpch_reqno = req->rpc_head.rpch_reqno;
resp->rpc_head.rpch_type = RUMPRPC_COPYIN_RESP;
memcpy(resp->rpc_data, req->rpc_addr, req->rpc_len);
kmem_free(req, req->rpc_head.rpch_flen);
dosend(sock, qent, (uint8_t *)resp, totlen, false);
kmem_free(resp, totlen);
put_qent(qent);
}
/*
* Client side. We can either get the results of an earlier syscall or
* get a request for a copyin/out.
*/
static void
recvthread(void *arg)
{
struct rumprpc_head rpch;
uint8_t *rpc;
int s = (uintptr_t)arg;
int error;
for (;;) {
error = read_n(s, (uint8_t *)&rpch, sizeof(rpch));
if (error)
panic("%d", error);
rpc = kmem_alloc(rpch.rpch_flen , KM_SLEEP);
error = read_n(s, rpc + sizeof(struct rumprpc_head),
rpch.rpch_flen - sizeof(struct rumprpc_head));
if (error)
panic("%d", error);
memcpy(rpc, &rpch, sizeof(rpch));
switch (rpch.rpch_type) {
case RUMPRPC_SYSCALL:
/* assert server */
wrkenqueue(handle_syscall, rpc);
break;
case RUMPRPC_SYSCALL_RESP:
/* assert client */
{
struct sysproxy_qent *qent;
mutex_enter(&recvmtx);
TAILQ_FOREACH(qent, &recvq, entries)
if (qent->reqno == rpch.rpch_reqno)
break;
if (!qent) {
mutex_exit(&recvmtx);
kmem_free(rpc, rpch.rpch_flen);
break;
}
TAILQ_REMOVE(&recvq, qent, entries);
qent->rpch_resp = (void *)rpc;
cv_signal(&qent->cv);
mutex_exit(&recvmtx);
break;
}
case RUMPRPC_COPYIN:
/* assert client */
wrkenqueue(handle_copyin, rpc);
break;
case RUMPRPC_COPYIN_RESP:
/* assert server */
{
struct sysproxy_qent *qent;
mutex_enter(&recvmtx);
TAILQ_FOREACH(qent, &recvq, entries)
if (qent->reqno == rpch.rpch_reqno)
break;
if (!qent) {
mutex_exit(&recvmtx);
kmem_free(rpc, rpch.rpch_flen);
break;
}
TAILQ_REMOVE(&recvq, qent, entries);
qent->rpch_resp = (void *)rpc;
cv_signal(&qent->cv);
mutex_exit(&recvmtx);
break;
}
case RUMPRPC_COPYOUT:
{
struct rumprpc_copydata *req = (void *)rpc;
memcpy(req->rpc_addr, req->rpc_data, req->rpc_len);
kmem_free(req, req->rpc_head.rpch_flen);
break;
}
default:
printf("invalid type %d\n", rpch.rpch_type);
};
}
}
/*
* Make a syscall to a remote site over a socket. I'm not really sure
* if this should use kernel or user networking. Currently it uses
* user networking, but could be changed.
*/
static int
rump_sysproxy_socket(int num, void *arg, uint8_t *data, size_t dlen,
register_t *retval)
{
struct sysproxy_qent *qent;
struct rumprpc_sysreq *call;
struct rumprpc_sysresp *resp;
size_t totlen = sizeof(*call) + dlen;
int s = (uintptr_t)arg;
int error;
qent = get_qent();
/* build request */
/* should we prefer multiple writes if dlen > magic_constant? */
call = kmem_alloc(totlen, KM_SLEEP);
call->rpc_head.rpch_flen = totlen;
call->rpc_head.rpch_reqno = qent->reqno;
call->rpc_head.rpch_type = RUMPRPC_SYSCALL;
call->rpc_sysnum = num;
memcpy(call->rpc_data, data, dlen);
dosend(s, qent, (uint8_t *)call, totlen, true);
kmem_free(call, totlen);
/*
* Wake up next sender or just toggle availability
*/
mutex_enter(&sendmtx);
if (TAILQ_EMPTY(&sendq)) {
sendavail = true;
} else {
cv_signal(&TAILQ_FIRST(&sendq)->cv);
}
mutex_exit(&sendmtx);
/* Wait for response */
mutex_enter(&recvmtx);
while (qent->rpch_resp == NULL)
cv_wait(&qent->cv, &recvmtx);
mutex_exit(&recvmtx);
resp = (struct rumprpc_sysresp *)qent->rpch_resp;
/* we trust our kernel */
KASSERT(resp->rpc_head.rpch_type == RUMPRPC_SYSCALL_RESP);
*retval = resp->rpc_retval;
error = resp->rpc_error;
kmem_free(resp, resp->rpc_head.rpch_flen);
put_qent(qent);
return error;
}
int
rump_sysproxy_socket_setup_client(int s)
{
int error;
error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
recvthread, (void *)(uintptr_t)s, NULL, "sysproxy_recv");
if (error)
return error;
mutex_init(&wrkmtx, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&sendmtx, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&recvmtx, MUTEX_DEFAULT, IPL_NONE);
error = rump_sysproxy_set(rump_sysproxy_socket, (void *)(uintptr_t)s);
/* XXX: handle */
sock = s;
return error;
}
int
rump_sysproxy_socket_setup_server(int s)
{
int error;
error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
recvthread, (void *)(uintptr_t)s, NULL, "sysproxy_recv");
if (error)
return error;
mutex_init(&wrkmtx, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&recvmtx, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&sendmtx, MUTEX_DEFAULT, IPL_NONE);
sock = s;
return 0;
}

View File

@ -0,0 +1,9 @@
# $NetBSD: Makefile,v 1.1 2009/04/29 17:51:47 pooka Exp $
#
PROG= sysproxy_client
NOMAN=
LDADD+= -lrumpvfs -lrump -lrumpuser -lpthread
.include <bsd.prog.mk>

View File

@ -0,0 +1,65 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <rump/rump.h>
#include <rump/rump_syscalls.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SERVPATH "/tmp/rump_sysproxy_test"
#define USE_UN
int
main()
{
struct stat sb[3];
int s, error;
size_t len;
int i;
#ifdef USE_UN
struct sockaddr_un sun;
s = socket(AF_LOCAL, SOCK_STREAM, 0);
if (s == -1)
err(1, "socket");
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL;
strcpy(sun.sun_path, SERVPATH);
if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) == -1)
err(1, "connect");
#else
struct sockaddr_in sin;
int x = 1;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1)
err(1, "socket");
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(12345);
sin.sin_addr.s_addr = inet_addr("10.181.181.1");
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
err(1, "connect");
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x)) == -1)
err(1, "setsockopt");
#endif
rump_init();
rump_sysproxy_socket_setup_client(s);
if (rump_sys_stat("/", &sb[1]) == -1)
err(1, "stat");
}

View File

@ -0,0 +1,10 @@
# $NetBSD: Makefile,v 1.1 2009/04/29 17:51:47 pooka Exp $
#
PROG= sysproxy_serv
NOMAN=
LDADD+= -lrump -lrumpuser -lpthread
LDADD+= -lrumpvfs
.include <bsd.prog.mk>

View File

@ -0,0 +1,95 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <rump/rump.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define SERVPATH "/tmp/rump_sysproxy_test"
#define USE_UN
static void
cleanup()
{
unlink(SERVPATH);
}
static void
sigint(int sig)
{
cleanup();
_exit(0);
}
static void
sigabrt(int sig)
{
cleanup();
abort();
}
int
main()
{
socklen_t slen;
int s, s2;
#ifdef USE_UN
struct sockaddr_un sun;
s = socket(AF_LOCAL, SOCK_STREAM, 0);
if (s == -1)
err(1, "socket");
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL;
strcpy(sun.sun_path, SERVPATH);
if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) == -1)
err(1, "bind");
atexit(cleanup);
signal(SIGINT, sigint);
signal(SIGSEGV, sigabrt);
if (listen(s, 1) == -1)
err(1, "listen");
slen = sizeof(sun);
s2 = accept(s, (struct sockaddr *)&sun, &slen);
if (s2 == -1)
err(1, "accept");
#else
struct sockaddr_in sin;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1)
err(1, "socket");
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(12345);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
err(1, "bind");
if (listen(s, 1) == -1)
err(1, "listen");
slen = sizeof(sin);
s2 = accept(s, (struct sockaddr *)&sin, &slen);
if (s2 == -1)
err(1, "accept");
#endif
rump_init();
rump_sysproxy_socket_setup_server(s2);
pause();
return 0;
}