diff options
author | Michael Neuling <mikey@neuling.org> | 2017-09-04 11:02:30 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-09-04 20:45:35 -0500 |
commit | 058e5839a150c2ce6512b553581d875eacf7e6a5 (patch) | |
tree | d0d85a200075f0aa26dd16dc5ae08826c63fb6a9 /external | |
parent | e221d3522737cf6ee04349a40045b357c4404aba (diff) | |
download | skiboot-058e5839a150c2ce6512b553581d875eacf7e6a5.zip skiboot-058e5839a150c2ce6512b553581d875eacf7e6a5.tar.gz skiboot-058e5839a150c2ce6512b553581d875eacf7e6a5.tar.bz2 |
mambo: Add mambo socket program
This adds a program that can be run inside a mambo simulator in linux
userspace which enables TCP sockets to be proxied in and out of the
simulator to the host.
Unlike mambo bogusnet, it's requires no linux or skiboot specific
drivers/infrastructure to run.
eg.
Run inside the simulator:
- to forward host ssh connections to sim ssh server
./mambo-socket-proxy -h 10022 -s 22
Then connect to port 10022 on your host
ssh -p 10022 localhost
- to allow http proxy access from inside the sim to local http proxy
./mambo-socket-proxy -b proxy.mynetwork -h 3128 -s 3128
Multiple connections are supported.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'external')
-rw-r--r-- | external/mambo/Makefile | 8 | ||||
-rw-r--r-- | external/mambo/mambo-socket-proxy.c | 359 |
2 files changed, 367 insertions, 0 deletions
diff --git a/external/mambo/Makefile b/external/mambo/Makefile new file mode 100644 index 0000000..fbc696e --- /dev/null +++ b/external/mambo/Makefile @@ -0,0 +1,8 @@ +CFLAGS=-O2 -m64 -pthread -Werror -Wall + +CC=$(CROSS)gcc + +all: mambo-socket-proxy + +clean: + rm -rf mambo-socket-proxy diff --git a/external/mambo/mambo-socket-proxy.c b/external/mambo/mambo-socket-proxy.c new file mode 100644 index 0000000..f3a1a2f --- /dev/null +++ b/external/mambo/mambo-socket-proxy.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2017 Michael Neuling <mikey@neuling.org>, IBM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Compile with: + * gcc -static -O2 mambo-socket-proxy.c -o mambo-socket-proxy -pthread + * Run inside the simulator: + * - to forward host ssh connections to sim ssh server + * ./mambo-socket-proxy -h 10022 -s 22 + * Then connect to port 10022 on your host + * ssh -p 10022 localhost + * - to allow http proxy access from inside the sim to local http proxy + * ./mambo-socket-proxy -b proxy.mynetwork -h 3128 -s 3128 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <getopt.h> + +#define CALL_TCL 86 +#define BOGUS_SOCKET_CONN_PROBE_CODE 224 +#define BOGUS_SOCKET_CONN_SEND_CODE 225 +#define BOGUS_SOCKET_CONN_RECV_CODE 226 + +static inline int callthru2(int command, unsigned long arg1, unsigned long arg2) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2)); + return (c); +} + +static inline int callthru3(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3)); + return (c); +} + +static inline int callthru4(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + register unsigned long a4 asm("r7") = arg4; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3), "r"(a4)); + return (c); +} + +static inline int callthru5(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + register unsigned long a4 asm("r7") = arg4; + register unsigned long a5 asm("r8") = arg5; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3), "r"(a4), "r"(a5)); + return (c); +} + +unsigned long callthru_tcl(const char *str, int strlen) +{ + return callthru2(CALL_TCL, (unsigned long)str, + (unsigned long)strlen); +} + +unsigned long bogus_socket_conn_probe(int dev, void *addr, int conn) +{ + return callthru3(BOGUS_SOCKET_CONN_PROBE_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)conn); +} + +unsigned long bogus_socket_conn_recv(int dev, void *addr, int maxlen, int conn) +{ + return callthru4(BOGUS_SOCKET_CONN_RECV_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)maxlen, + (unsigned long)conn); +} + +unsigned long bogus_socket_conn_send(int dev, void *addr, int maxlen, int conn) +{ + return callthru5(BOGUS_SOCKET_CONN_SEND_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)maxlen, + 0, + (unsigned long)conn); +} + +#define BUF_MAX 1024 + +struct sock_info { + char *host; + int sock; + int dev; + int open; + int conn; +}; + +void *recv_thread(void *ptr) +{ + struct timeval timeout; + struct sock_info *si = ptr; + char buf[BUF_MAX]; + int len; + fd_set set; + + /* 1 sec */ + + + while(1) { + FD_ZERO(&set); + FD_SET(si->sock, &set); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + /* Set timeout to 1 second */ + len = select(si->sock+1, &set, NULL, NULL, &timeout); + if (len <= 0) /* timeout */ + len = -1; + else /* Receive from mambo tcp server */ + len = recv(si->sock, &buf, BUF_MAX, 0); + if (len == 0) { + si->open = 0; + return NULL; /* closed */ + } + if (len != -1) { + bogus_socket_conn_send(si->dev, &buf, len, si->conn); + } + if (!si->open) + return NULL; + } +} + +#define POLL_MAX_NS 10000000 + +void *send_thread(void *ptr) +{ + struct sock_info *si = ptr; + char buf[BUF_MAX]; + int len; + struct timespec t; + int fault_retry = 16; + + t.tv_sec = 0; + t.tv_nsec = POLL_MAX_NS; + + while(1) { + /* Send to mambo tcp server */ + len = bogus_socket_conn_recv(si->dev, &buf, BUF_MAX, si->conn); + if (len == -3 && fault_retry--) { + /* Page fault. Touch the buf and try again */ + memset(buf, 0, BUF_MAX); + continue; + } + fault_retry = 16; + + if (len == -1) /* EAGAIN */ + nanosleep(&t , NULL); + else if (len > 0) + send(si->sock, &buf, len, 0); + else { + si->open = 0; + return NULL; /* closed */ + } + if (!si->open) + return NULL; + } + +} + +void *connect_sockets(void *ptr) +{ + struct sock_info *si = ptr; + pthread_t recv, send; + unsigned long rc = 0; + + if (pthread_create(&recv, NULL, recv_thread, si) || + pthread_create(&send, NULL, send_thread, si)) { + rc = -1; + goto out; + } + + if (pthread_join(recv, NULL) || pthread_join(send, NULL)) { + rc = -1; + goto out; + } + +out: + /* FIXME: Do shutdown better */ + shutdown(si->sock, SHUT_WR); + si->open = 0; + free(si); + return (void *)rc; +} + +void print_usage() { + printf("Usage:\n"); + printf(" mambo-socket-proxy [-b <host>] -h <host port> -s <sim port>\n"); + printf("\n"); + printf(" -h <host port> : Port on the host to forward\n"); + printf(" -s <host port> : Port in the sim to forward\n"); + printf(" -b <host machine> : Connect sim port to host network\n"); + printf("\n"); +} + +int main (int argc, char *argv[]) +{ + char cmd[128]; + struct sockaddr_in ser, client; + pthread_t sockets_thread; + struct sock_info *si; + int sock, conn, rc = 0, option = 0, one_shot = 0, c, sock_desc = 0; + char *host = NULL; + int host_port = -1, sim_port = -1; + int dev = 1; /* backwards starts at 1 so forwards can use 0 */ + + while ((option = getopt(argc, argv,"rb:h:s:")) != -1) { + switch (option) { + case 'b' : + host = optarg; + break; + case 'h' : + host_port = atoi(optarg); + break; + case 's' : + sim_port = atoi(optarg); + break; + default: + print_usage(); + exit(1); + } + } + + if (host_port == -1 || sim_port ==-1) { + print_usage(); + exit(EXIT_FAILURE); + } + + /* + * A host/backwards connection will use dev=0 and conn >= 0. + * The forwards connection will use dev >= 1 and conn=0 + */ + if (host) { + sock_desc = socket(PF_INET, SOCK_STREAM, 0); + ser.sin_family = AF_INET; + ser.sin_addr.s_addr = INADDR_ANY; + ser.sin_port = htons(sim_port); + + if (bind(sock_desc, (struct sockaddr *) &ser, sizeof(ser)) < 0) { + perror("Can't connect to sim port"); + rc = -1; + goto out; + } + + listen(sock_desc, 3); + } else { + /* + * Cleaning up old bogus socket. + */ + sprintf(cmd, "mysim bogus socket cleanup"); + callthru_tcl(cmd, strlen(cmd)); + sleep(1); /* Cleanup takes a while */ + sprintf(cmd, "mysim bogus socket init 0 server " + "127.0.0.1 %i poll 0 nonblock", host_port); + callthru_tcl(cmd, strlen(cmd)); + } + + while (1) { + + if (host) { + sock = accept(sock_desc, (struct sockaddr *)&client, (socklen_t*)&c); + if (sock < 0) { + perror("accept failed"); + rc = -1; + goto out; + } + + sprintf(cmd, "mysim bogus socket init %i client %s %i poll 0", + dev, host, host_port); + callthru_tcl(cmd, strlen(cmd)); + while (bogus_socket_conn_probe(dev, NULL, 0) == -1) + sleep(1); + } else { + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + do { + conn = bogus_socket_conn_probe(0, NULL, -1); + nanosleep(&t , NULL); + } while (conn == -1); + + sock = socket(PF_INET, SOCK_STREAM, 0); + ser.sin_family = AF_INET; + ser.sin_port = htons(sim_port); + ser.sin_addr.s_addr = inet_addr("127.0.0.1"); + memset(ser.sin_zero, '\0', sizeof ser.sin_zero); + + if (connect(sock, (struct sockaddr *) &ser, sizeof(ser))) { + perror("Can't connect to sim port"); + rc = -1; + goto out; + } + } + + si = malloc(sizeof(struct sock_info)); + si->host = host; + si->sock = sock; + si->dev = host?dev:0; + si->open = 1; + si->conn = host?0:conn; + + if (pthread_create(&sockets_thread, NULL, connect_sockets, si)) { + rc = -1; + goto out; + } + + if (one_shot) + break; + ++dev; // FIXME: do a real allocator + } +out: + exit(rc); +} |