@@ -374,6 +374,7 @@ long tracecmd_flush_recording(struct tracecmd_recorder *recorder);
enum tracecmd_msg_flags {
TRACECMD_MSG_FL_USE_TCP = 1 << 0,
+ TRACECMD_MSG_FL_USE_VSOCK = 1 << 1,
};
/* for both client and server */
@@ -214,10 +214,14 @@ static int make_tinit(struct tracecmd_msg_handle *msg_handle,
int opt_num = 0;
int data_size = 0;
- if (msg_handle->flags & TRACECMD_MSG_FL_USE_TCP) {
+ if (msg_handle->flags & (TRACECMD_MSG_FL_USE_TCP |
+ TRACECMD_MSG_FL_USE_VSOCK)) {
+ msg->buf = msg_handle->flags & TRACECMD_MSG_FL_USE_TCP ?
+ strdup("tcp") : strdup("vsock");
+ if (!msg->buf)
+ return -1;
opt_num++;
- msg->buf = strdup("tcp");
- data_size += 4;
+ data_size += strlen(msg->buf) + 1;
}
msg->tinit.cpus = htonl(cpu_count);
@@ -566,11 +570,14 @@ out:
static bool process_option(struct tracecmd_msg_handle *msg_handle,
const char *opt)
{
- /* currently the only option we have is to use TCP */
if (strcmp(opt, "tcp") == 0) {
msg_handle->flags |= TRACECMD_MSG_FL_USE_TCP;
return true;
}
+ if (strcmp(opt, "vsock") == 0) {
+ msg_handle->flags |= TRACECMD_MSG_FL_USE_VSOCK;
+ return true;
+ }
return false;
}
@@ -45,6 +45,7 @@ int trace_set_verbose(char *level);
enum port_type {
USE_UDP,
USE_TCP,
+ USE_VSOCK
};
struct pid_record_data {
@@ -343,6 +344,8 @@ int trace_make_vsock(unsigned int port);
int trace_get_vsock_port(int sd, unsigned int *port);
int trace_open_vsock(unsigned int cid, unsigned int port);
+int get_local_cid(unsigned int *cid);
+
char *trace_get_guest_file(const char *file, const char *guest);
#ifdef VSOCK
@@ -19,6 +19,10 @@
#include <signal.h>
#include <errno.h>
+#ifdef VSOCK
+#include <linux/vm_sockets.h>
+#endif
+
#include "trace-local.h"
#include "trace-msg.h"
@@ -34,6 +38,8 @@ static char *output_dir;
static char *default_output_file = "trace";
static char *output_file;
+static bool use_vsock;
+
static int backlog = 5;
static int do_daemon;
@@ -141,7 +147,11 @@ static int process_child(int sfd, const char *host, const char *port,
int cpu, int page_size, enum port_type type)
{
struct sockaddr_storage peer_addr;
- socklen_t peer_addr_len;
+#ifdef VSOCK
+ struct sockaddr_vm vm_addr;
+#endif
+ struct sockaddr *addr;
+ socklen_t addr_len;
char buf[page_size];
char *tempfile;
int left;
@@ -161,10 +171,20 @@ static int process_child(int sfd, const char *host, const char *port,
pdie("creating %s", tempfile);
if (type == USE_TCP) {
+ addr = (struct sockaddr *)&peer_addr;
+ addr_len = sizeof(peer_addr);
+#ifdef VSOCK
+ } else if (type == USE_VSOCK) {
+ addr = (struct sockaddr *)&vm_addr;
+ addr_len = sizeof(vm_addr);
+#endif
+ }
+
+ if (type == USE_TCP || type == USE_VSOCK) {
if (listen(sfd, backlog) < 0)
pdie("listen");
- peer_addr_len = sizeof(peer_addr);
- cfd = accept(sfd, (struct sockaddr *)&peer_addr, &peer_addr_len);
+
+ cfd = accept(sfd, addr, &addr_len);
if (cfd < 0 && errno == EINTR)
goto done;
if (cfd < 0)
@@ -202,6 +222,18 @@ static int process_child(int sfd, const char *host, const char *port,
exit(0);
}
+static int setup_vsock_port(int start_port, int *sfd)
+{
+ int sd;
+
+ sd = trace_vsock_make(start_port);
+ if (sd < 0)
+ return -errno;
+ *sfd = sd;
+
+ return start_port;
+}
+
#define START_PORT_SEARCH 1500
#define MAX_PORT_SEARCH 6000
@@ -213,6 +245,8 @@ static int bind_a_port(int start_port, int *sfd, enum port_type type)
int s;
int num_port = start_port;
+ if (type == USE_VSOCK)
+ return setup_vsock_port(start_port, sfd);
again:
snprintf(buf, BUFSIZ, "%d", num_port);
@@ -478,6 +512,8 @@ static int *create_all_readers(const char *node, const char *port,
if (msg_handle->flags & TRACECMD_MSG_FL_USE_TCP)
port_type = USE_TCP;
+ else if (msg_handle->flags & TRACECMD_MSG_FL_USE_VSOCK)
+ port_type = USE_VSOCK;
port_array = malloc(sizeof(*port_array) * cpus);
if (!port_array)
@@ -700,8 +736,8 @@ static int do_fork(int cfd)
return 0;
}
-static int do_connection(int cfd, struct sockaddr_storage *peer_addr,
- socklen_t peer_addr_len)
+static int do_connection(int cfd, struct sockaddr *addr,
+ socklen_t addr_len)
{
struct tracecmd_msg_handle *msg_handle;
char host[NI_MAXHOST], service[NI_MAXSERV];
@@ -714,17 +750,25 @@ static int do_connection(int cfd, struct sockaddr_storage *peer_addr,
msg_handle = tracecmd_msg_handle_alloc(cfd, 0);
- s = getnameinfo((struct sockaddr *)peer_addr, peer_addr_len,
- host, NI_MAXHOST,
- service, NI_MAXSERV, NI_NUMERICSERV);
-
- if (s == 0)
- tracecmd_plog("Connected with %s:%s\n", host, service);
- else {
- tracecmd_plog("Error with getnameinfo: %s\n", gai_strerror(s));
- close(cfd);
- tracecmd_msg_handle_close(msg_handle);
- return -1;
+ if (use_vsock) {
+#ifdef VSOCK
+ struct sockaddr_vm *vm_addr = (struct sockaddr_vm *)addr;
+ snprintf(host, NI_MAXHOST, "V%d", vm_addr->svm_cid);
+ snprintf(service, NI_MAXSERV, "%d", vm_addr->svm_port);
+#endif
+ } else {
+ s = getnameinfo((struct sockaddr *)addr, addr_len,
+ host, NI_MAXHOST,
+ service, NI_MAXSERV, NI_NUMERICSERV);
+
+ if (s == 0)
+ tracecmd_plog("Connected with %s:%s\n", host, service);
+ else {
+ tracecmd_plog("Error with getnameinfo: %s\n", gai_strerror(s));
+ close(cfd);
+ tracecmd_msg_handle_close(msg_handle);
+ return -1;
+ }
}
process_client(msg_handle, host, service);
@@ -816,14 +860,25 @@ static void clean_up(void)
static void do_accept_loop(int sfd)
{
struct sockaddr_storage peer_addr;
- socklen_t peer_addr_len;
+#ifdef VSOCK
+ struct sockaddr_vm vm_addr;
+#endif
+ struct sockaddr *addr;
+ socklen_t addr_len;
int cfd, pid;
- peer_addr_len = sizeof(peer_addr);
+ if (use_vsock) {
+#ifdef VSOCK
+ addr = (struct sockaddr *)&vm_addr;
+ addr_len = sizeof(vm_addr);
+#endif
+ } else {
+ addr = (struct sockaddr *)&peer_addr;
+ addr_len = sizeof(peer_addr);
+ }
do {
- cfd = accept(sfd, (struct sockaddr *)&peer_addr,
- &peer_addr_len);
+ cfd = accept(sfd, addr, &addr_len);
if (cfd < 0 && errno == EINTR) {
clean_up();
continue;
@@ -831,7 +886,7 @@ static void do_accept_loop(int sfd)
if (cfd < 0)
pdie("connecting");
- pid = do_connection(cfd, &peer_addr, peer_addr_len);
+ pid = do_connection(cfd, addr, addr_len);
if (pid > 0)
add_process(pid);
@@ -866,17 +921,28 @@ static void sigstub(int sig)
{
}
-static void do_listen(char *port)
+static int get_vsock(const char *port)
+{
+ unsigned int cid;
+ int sd;
+
+ sd = trace_vsock_make(atoi(port));
+ if (sd < 0)
+ return sd;
+
+ cid = trace_vsock_local_cid();
+ if (cid >= 0)
+ printf("listening on @%u:%s\n", cid, port);
+
+ return sd;
+}
+
+static int get_network(char *port)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
- if (!tracecmd_get_debug())
- signal_setup(SIGCHLD, sigstub);
-
- make_pid_file();
-
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
@@ -903,6 +969,24 @@ static void do_listen(char *port)
freeaddrinfo(result);
+ return sfd;
+}
+
+static void do_listen(char *port)
+{
+ int sfd;
+
+ if (!tracecmd_get_debug())
+ signal_setup(SIGCHLD, sigstub);
+
+ make_pid_file();
+
+ if (use_vsock)
+ sfd = get_vsock(port);
+ else
+ sfd = get_network(port);
+
+
if (listen(sfd, backlog) < 0)
pdie("listen");
@@ -949,7 +1033,7 @@ void trace_listen(int argc, char **argv)
{NULL, 0, NULL, 0}
};
- c = getopt_long (argc-1, argv+1, "+hp:o:d:l:D",
+ c = getopt_long (argc-1, argv+1, "+hp:Vo:d:l:D",
long_options, &option_index);
if (c == -1)
break;
@@ -963,6 +1047,9 @@ void trace_listen(int argc, char **argv)
case 'd':
output_dir = optarg;
break;
+ case 'V':
+ use_vsock = true;
+ break;
case 'o':
output_file = optarg;
break;
@@ -3128,6 +3128,9 @@ static int connect_port(const char *host, unsigned int port)
snprintf(buf, BUFSIZ, "%u", port);
+ if (port_type == USE_VSOCK)
+ return trace_vsock_open(atoi(host), port);
+
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = port_type == USE_TCP ? SOCK_STREAM : SOCK_DGRAM;
@@ -3531,11 +3534,33 @@ static void check_protocol_version(struct tracecmd_msg_handle *msg_handle)
}
}
-static struct tracecmd_msg_handle *setup_network(struct buffer_instance *instance)
+static int connect_vsock(char *vhost)
+{
+ char *cid;
+ char *port;
+ char *p;
+ int sd;
+
+ host = strdup(vhost);
+ if (!host)
+ die("alloctating server");
+
+ cid = strtok_r(host, ":", &p);
+ port = strtok_r(NULL, "", &p);
+
+ if (!port)
+ die("vsocket must have format of 'CID:PORT'");
+
+ sd = trace_vsock_open(atoi(cid), atoi(port));
+
+ return sd;
+}
+
+static int connect_ip(char *host)
{
- struct tracecmd_msg_handle *msg_handle = NULL;
struct addrinfo hints;
struct addrinfo *result, *rp;
+ char *thost = NULL;
int sfd, s;
char *server;
char *port;
@@ -3548,8 +3573,8 @@ static struct tracecmd_msg_handle *setup_network(struct buffer_instance *instanc
port = host;
host = server;
} else {
- host = strdup(host);
- if (!host)
+ thost = strdup(host);
+ if (!thost)
die("alloctating server");
server = strtok_r(host, ":", &p);
port = strtok_r(NULL, ":", &p);
@@ -3559,7 +3584,6 @@ static struct tracecmd_msg_handle *setup_network(struct buffer_instance *instanc
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
-again:
s = getaddrinfo(server, port, &hints, &result);
if (s != 0)
die("getaddrinfo: %s", gai_strerror(s));
@@ -3579,6 +3603,27 @@ again:
die("Can not connect to %s:%s", server, port);
freeaddrinfo(result);
+ free(thost);
+
+ return sfd;
+}
+
+static struct tracecmd_msg_handle *setup_network(struct buffer_instance *instance)
+{
+ struct tracecmd_msg_handle *msg_handle = NULL;
+ int sfd;
+
+again:
+ switch (port_type) {
+ case USE_VSOCK:
+ sfd = connect_vsock(host);
+ break;
+ default:
+ sfd = connect_ip(host);
+ }
+
+ if (sfd < 0)
+ return NULL;
if (msg_handle) {
msg_handle->fd = sfd;
@@ -3591,14 +3636,23 @@ again:
msg_handle->version = V3_PROTOCOL;
}
- if (port_type == USE_TCP)
+ switch (port_type) {
+ case USE_TCP:
msg_handle->flags |= TRACECMD_MSG_FL_USE_TCP;
+ break;
+ case USE_VSOCK:
+ msg_handle->flags |= TRACECMD_MSG_FL_USE_VSOCK;
+ break;
+ default:
+ break;
+ }
if (msg_handle->version == V3_PROTOCOL) {
check_protocol_version(msg_handle);
if (msg_handle->version == V1_PROTOCOL) {
/* reconnect to the server for using the v1 protocol */
close(sfd);
+ free(host);
goto again;
}
communicate_with_listener_v3(msg_handle, &instance->client_ports);
@@ -3649,6 +3703,8 @@ setup_connection(struct buffer_instance *instance, struct common_record_context
int ret;
msg_handle = setup_network(instance);
+ if (!msg_handle)
+ die("Failed to make connection");
/* Now create the handle through this socket */
if (msg_handle->version == V3_PROTOCOL) {
@@ -6159,7 +6215,7 @@ static void parse_record_options(int argc,
if (IS_EXTRACT(ctx))
opts = "+haf:Fp:co:O:sr:g:l:n:P:N:tb:B:ksiT";
else
- opts = "+hae:f:FA:p:cC:dDGo:O:s:r:vg:l:n:P:N:tb:R:B:ksSiTm:M:H:q";
+ opts = "+hae:f:FA:p:cC:dDGo:O:s:r:V:vg:l:n:P:N:tb:R:B:ksSiTm:M:H:q";
c = getopt_long (argc-1, argv+1, opts, long_options, &option_index);
if (c == -1)
break;
@@ -6451,6 +6507,17 @@ static void parse_record_options(int argc,
die("-N incompatible with -o");
host = optarg;
break;
+ case 'V':
+ cmd_check_die(ctx, CMD_set, *(argv+1), "-V");
+ if (!IS_RECORD(ctx))
+ die("-V only available with record");
+ if (IS_RECORD_AGENT(ctx))
+ die("-V incompatible with agent recording");
+ if (ctx->output)
+ die("-V incompatible with -o");
+ host = optarg;
+ port_type = USE_VSOCK;
+ break;
case 'm':
if (max_kb)
die("-m can only be specified once");