tap-vsockd: support daemonization via a --daemon arg

We daemonize after checking the command-line and binding/connecting
the socket and creating the tap device. Only the ethernet frame
processing happens afterwards.

This patch also includes a new well-known service GUID for the
VPN-proxy ethernet service.

Signed-off-by: David Scott <dave.scott@docker.com>
This commit is contained in:
David Scott 2016-05-14 20:38:56 +01:00
parent f636321b81
commit a1d91d2a3d

View File

@ -27,10 +27,12 @@
#include "compat.h" #include "compat.h"
#include "protocol.h" #include "protocol.h"
int debug_flag = 0; int daemon_flag = 0;
int listen_flag = 0; int listen_flag = 0;
int connect_flag = 0; int connect_flag = 0;
char *default_sid = "30D48B34-7D27-4B0B-AAAF-BBBED334DD59";
int alloc_tap(const char *dev) { int alloc_tap(const char *dev) {
int fd; int fd;
struct ifreq ifr; struct ifreq ifr;
@ -219,7 +221,7 @@ static void* tap_to_vmnet(void *arg)
/* Handle a connection. Handshake with the com.docker.slirp process and start /* Handle a connection. Handshake with the com.docker.slirp process and start
* exchanging ethernet frames between the socket and the tap device. * exchanging ethernet frames between the socket and the tap device.
*/ */
static void handle(SOCKET fd, const char *tap) static void handle(SOCKET fd, char *tap, int tapfd)
{ {
struct connection connection; struct connection connection;
pthread_t v2t, t2v; pthread_t v2t, t2v;
@ -231,7 +233,6 @@ static void handle(SOCKET fd, const char *tap)
connection.vif.mac[3], connection.vif.mac[4], connection.vif.mac[5] connection.vif.mac[3], connection.vif.mac[4], connection.vif.mac[5]
); );
int tapfd = alloc_tap(tap);
set_macaddr(tap, &connection.vif.mac[0]); set_macaddr(tap, &connection.vif.mac[0]);
connection.tapfd = tapfd; connection.tapfd = tapfd;
@ -311,17 +312,11 @@ static int connect_socket(GUID serviceid) {
return sock; return sock;
} }
static int accept_socket(SOCKET lsock) {
/* Server:
* accept() in an endless loop, handle a connection at a time
*/
static void accept_forever(SOCKET lsock, const char *tap)
{
SOCKET csock = INVALID_SOCKET; SOCKET csock = INVALID_SOCKET;
SOCKADDR_HV sac; SOCKADDR_HV sac;
socklen_t socklen = sizeof(sac); socklen_t socklen = sizeof(sac);
while(1) {
csock = accept(lsock, (struct sockaddr *)&sac, &socklen); csock = accept(lsock, (struct sockaddr *)&sac, &socklen);
if (csock == INVALID_SOCKET) { if (csock == INVALID_SOCKET) {
sockerr("accept()"); sockerr("accept()");
@ -331,10 +326,7 @@ static void accept_forever(SOCKET lsock, const char *tap)
printf("Connect from: "GUID_FMT":"GUID_FMT"\n", printf("Connect from: "GUID_FMT":"GUID_FMT"\n",
GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId));
return csock;
handle(csock, tap);
closesocket(csock);
}
} }
void write_pidfile(const char *pidfile) { void write_pidfile(const char *pidfile) {
@ -362,16 +354,44 @@ void write_pidfile(const char *pidfile) {
free(pid_s); free(pid_s);
} }
void daemonize(const char *pidfile){
pid_t pid = fork ();
if (pid == -1) {
syslog(LOG_CRIT, "Failed to fork()");
exit(1);
}
else if (pid != 0)
exit(0);
if (setsid () == -1) {
syslog(LOG_CRIT, "Failed to setsid()");
exit(1);
}
if (chdir ("/") == -1) {
syslog(LOG_CRIT, "Failed to chdir()");
exit(1);
}
int null = open("/dev/null", O_RDWR);
dup2(null, STDIN_FILENO);
dup2(null, STDOUT_FILENO);
dup2(null, STDERR_FILENO);
close(null);
if (pidfile) write_pidfile(pidfile);
}
void usage(char *name) void usage(char *name)
{ {
printf("%s: [--debug] [--tap <name>] [--serviceid <guid>] [--pid <file>]\n", name); printf("%s usage:\n", name);
printf("\t[--daemon] [--tap <name>] [--serviceid <guid>] [--pid <file>]\n");
printf("\t[--listen | --connect]\n\n"); printf("\t[--listen | --connect]\n\n");
printf("--debug: log to stderr as well as syslog\n"); printf("where\n");
printf("--tap <name>: create a tap device with the given name (defaults to eth1)\n"); printf("\t--daemonize: run as a background daemon\n");
printf("--serviceid <guid>: use <guid> as the well-known service GUID\n"); printf("\t--tap <name>: create a tap device with the given name\n");
printf("--pid <file>: write a pid to the given file\n"); printf("\t (defaults to eth1)\n");
printf("--listen: listen forever for incoming AF_HVSOCK connections\n"); printf("\t--serviceid <guid>: use <guid> as the well-known service GUID\n");
printf("--connect: connect to the parent partition\n"); printf("\t (defaults to %s)\n", default_sid);
printf("\t--pid <file>: write a pid to the given file\n");
printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n");
printf("\t--connect: connect to the parent partition\n");
} }
int __cdecl main(int argc, char **argv) int __cdecl main(int argc, char **argv)
@ -380,7 +400,7 @@ int __cdecl main(int argc, char **argv)
GUID sid; GUID sid;
int c; int c;
/* Defaults to a testing GUID */ /* Defaults to a testing GUID */
char *serviceid = "3049197C-9A4E-4FBF-9367-97F792F16994"; char *serviceid = default_sid;
char *tap = "eth1"; char *tap = "eth1";
char *pidfile = NULL; char *pidfile = NULL;
@ -388,7 +408,7 @@ int __cdecl main(int argc, char **argv)
while (1) { while (1) {
static struct option long_options[] = { static struct option long_options[] = {
/* These options set a flag. */ /* These options set a flag. */
{"debug", no_argument, &debug_flag, 1}, {"daemon", no_argument, &daemon_flag, 1},
{"serviceid", required_argument, NULL, 's'}, {"serviceid", required_argument, NULL, 's'},
{"tap", required_argument, NULL, 't'}, {"tap", required_argument, NULL, 't'},
{"pidfile", required_argument, NULL, 'p'}, {"pidfile", required_argument, NULL, 'p'},
@ -403,7 +423,7 @@ int __cdecl main(int argc, char **argv)
switch (c) { switch (c) {
case 'd': case 'd':
debug_flag = 1; daemon_flag = 1;
break; break;
case 's': case 's':
serviceid = optarg; serviceid = optarg;
@ -425,8 +445,12 @@ int __cdecl main(int argc, char **argv)
fprintf(stderr, "Please supply either the --listen or --connect flag, but not both.\n"); fprintf(stderr, "Please supply either the --listen or --connect flag, but not both.\n");
exit(1); exit(1);
} }
if (daemon_flag && !pidfile){
fprintf(stderr, "For daemon mode, please supply a --pidfile argument.\n");
exit(1);
}
int log_flags = LOG_CONS | LOG_NDELAY; int log_flags = LOG_CONS | LOG_NDELAY;
if (debug_flag) { if (!daemon_flag) {
log_flags |= LOG_PERROR; log_flags |= LOG_PERROR;
} }
openlog(argv[0], log_flags, LOG_DAEMON); openlog(argv[0], log_flags, LOG_DAEMON);
@ -438,14 +462,19 @@ int __cdecl main(int argc, char **argv)
exit(1); exit(1);
} }
SOCKET sock = INVALID_SOCKET;
if (listen_flag) { if (listen_flag) {
syslog(LOG_INFO, "starting in listening mode with serviceid=%s and tap=%s", serviceid, tap); syslog(LOG_INFO, "starting in listening mode with serviceid=%s and tap=%s", serviceid, tap);
int socket = create_listening_socket(sid); SOCKET lsocket = create_listening_socket(sid);
accept_forever(socket, tap); sock = accept_socket(lsocket);
exit(0); } else {
}
syslog(LOG_INFO, "starting in connect mode with serviceid=%s and tap=%s", serviceid, tap); syslog(LOG_INFO, "starting in connect mode with serviceid=%s and tap=%s", serviceid, tap);
int socket = connect_socket(sid); sock = connect_socket(sid);
handle(socket, tap); }
return 0; /* Bring up the tap device before we daemonize */
int tapfd = alloc_tap(tap);
if (daemon_flag) daemonize(pidfile);
handle(sock, tap, tapfd);
exit(0);
} }