@@ -190,6 +190,7 @@ enum buffer_instance_flags {
BUFFER_FL_HAS_CLOCK = 1 << 4,
BUFFER_FL_TSC2NSEC = 1 << 5,
BUFFER_FL_NETWORK = 1 << 6,
+ BUFFER_FL_PROXY = 1 << 7,
};
struct func_list {
@@ -305,6 +306,7 @@ extern struct buffer_instance *first_instance;
#define is_agent(instance) ((instance)->flags & BUFFER_FL_AGENT)
#define is_guest(instance) ((instance)->flags & BUFFER_FL_GUEST)
+#define is_proxy(instance) ((instance)->flags & BUFFER_FL_PROXY)
#define is_network(instance) ((instance)->flags & BUFFER_FL_NETWORK)
#define START_PORT_SEARCH 1500
@@ -144,17 +144,22 @@ static int wait_for_connection(int fd)
return sd;
}
-static void agent_handle(int sd, int nr_cpus, int page_size, const char *network)
+static void agent_handle(int sd, int nr_cpus, int page_size,
+ int cid, int rcid, const char *network)
{
struct tracecmd_tsync_protos *tsync_protos = NULL;
struct tracecmd_time_sync *tsync = NULL;
struct tracecmd_msg_handle *msg_handle;
const char *tsync_proto = NULL;
+ unsigned long long peer_trace_id;
unsigned long long trace_id;
+ unsigned long flags = rcid >= 0 ? TRACECMD_MSG_FL_PROXY : 0;
unsigned int remote_id;
unsigned int local_id;
unsigned int tsync_port = 0;
unsigned int *ports;
+ unsigned int client_cpus = 0;
+ unsigned int guests = 0;
char **argv = NULL;
int argc = 0;
bool use_fifos;
@@ -167,13 +172,20 @@ static void agent_handle(int sd, int nr_cpus, int page_size, const char *network
if (!fds || !ports)
die("Failed to allocate memory");
- msg_handle = tracecmd_msg_handle_alloc(sd, 0);
+ msg_handle = tracecmd_msg_handle_alloc(sd, flags);
if (!msg_handle)
die("Failed to allocate message handle");
- ret = tracecmd_msg_recv_trace_req(msg_handle, &argc, &argv,
- &use_fifos, &trace_id,
- &tsync_protos);
+ if (rcid >= 0)
+ ret = tracecmd_msg_recv_trace_proxy(msg_handle, &argc, &argv,
+ &use_fifos, &peer_trace_id,
+ &tsync_protos,
+ &client_cpus,
+ &guests);
+ else
+ ret = tracecmd_msg_recv_trace_req(msg_handle, &argc, &argv,
+ &use_fifos, &peer_trace_id,
+ &tsync_protos);
if (ret < 0)
die("Failed to receive trace request");
@@ -270,14 +282,15 @@ static pid_t do_fork()
return fork();
}
-static void agent_serve(unsigned int port, bool do_daemon, const char *network)
+static void agent_serve(unsigned int port, bool do_daemon, int proxy_id,
+ const char *network)
{
struct sockaddr_storage net_addr;
struct sockaddr *addr = NULL;
socklen_t *addr_len_p = NULL;
socklen_t addr_len = sizeof(net_addr);
int sd, cd, nr_cpus;
- unsigned int cid;
+ unsigned int cid = -1, rcid = -1;
pid_t pid;
signal(SIGCHLD, handle_sigchld);
@@ -316,6 +329,21 @@ static void agent_serve(unsigned int port, bool do_daemon, const char *network)
continue;
die("accept");
}
+ if (proxy_id >= 0) {
+ /* Only works with vsockets */
+ if (get_vsocket_params(cd, NULL, &rcid) < 0) {
+ dprint("Failed to find connected cid");
+ close(cd);
+ continue;
+ }
+ if (rcid != proxy_id) {
+ dprint("Cid %d does not match expected cid %d\n",
+ rcid, proxy_id);
+ close(cd);
+ continue;
+ }
+ }
+
if (tracecmd_get_debug())
trace_print_connection(cd, network);
@@ -332,7 +360,7 @@ static void agent_serve(unsigned int port, bool do_daemon, const char *network)
if (pid == 0) {
close(sd);
signal(SIGCHLD, SIG_DFL);
- agent_handle(cd, nr_cpus, page_size, network);
+ agent_handle(cd, nr_cpus, page_size, cid, rcid, network);
}
if (pid > 0)
handler_pid = pid;
@@ -352,6 +380,7 @@ void trace_agent(int argc, char **argv)
bool do_daemon = false;
unsigned int port = TRACE_AGENT_DEFAULT_PORT;
const char *network = NULL;
+ int proxy_id = -1;
if (argc < 2)
usage(argv);
@@ -369,7 +398,7 @@ void trace_agent(int argc, char **argv)
{NULL, 0, NULL, 0}
};
- c = getopt_long(argc-1, argv+1, "+hp:DN:",
+ c = getopt_long(argc-1, argv+1, "+hp:DN:P:",
long_options, &option_index);
if (c == -1)
break;
@@ -382,10 +411,17 @@ void trace_agent(int argc, char **argv)
break;
case 'p':
port = atoi(optarg);
+ if (proxy_id >= 0)
+ die("-N cannot be used with -P");
break;
case 'D':
do_daemon = true;
break;
+ case 'P':
+ proxy_id = atoi(optarg);
+ if (network)
+ die("-P cannot be used with -N");
+ break;
case DO_DEBUG:
tracecmd_set_debug(true);
break;
@@ -401,5 +437,5 @@ void trace_agent(int argc, char **argv)
if (optind < argc-1)
usage(argv);
- agent_serve(port, do_daemon, network);
+ agent_serve(port, do_daemon, proxy_id, network);
}
@@ -3862,6 +3862,7 @@ static void connect_to_agent(struct common_record_context *ctx,
unsigned int *ports;
int i, *fds = NULL;
bool use_fifos = false;
+ int siblings = 0;
if (!no_fifos) {
nr_fifos = open_guest_fifos(instance->name, &fds);
@@ -3892,11 +3893,19 @@ static void connect_to_agent(struct common_record_context *ctx,
if (instance->tsync_loop_interval >= 0)
tracecmd_tsync_proto_getall(&protos, instance->clock, role);
- ret = tracecmd_msg_send_trace_req(msg_handle, instance->argc,
- instance->argv, use_fifos,
- top_instance.trace_id, protos);
+ if (is_proxy(instance))
+ ret = tracecmd_msg_send_trace_proxy(msg_handle, instance->argc,
+ instance->argv, use_fifos,
+ top_instance.trace_id, protos,
+ tracecmd_count_cpus(),
+ siblings);
+ else
+ ret = tracecmd_msg_send_trace_req(msg_handle, instance->argc,
+ instance->argv, use_fifos,
+ top_instance.trace_id, protos);
if (ret < 0)
- die("Failed to send trace request");
+ die("Failed to send trace %s",
+ is_proxy(instance) ? "proxy" : "request");
if (protos) {
free(protos->names);
@@ -5623,6 +5632,7 @@ enum {
OPT_cmdlines_size = 258,
OPT_poll = 259,
OPT_name = 260,
+ OPT_proxy = 261
};
void trace_stop(int argc, char **argv)
@@ -6005,6 +6015,7 @@ static void parse_record_options(int argc,
char *sav;
int name_counter = 0;
int negative = 0;
+ bool is_proxy = false;
struct buffer_instance *instance, *del_list = NULL;
int do_children = 0;
int fpids_count = 0;
@@ -6045,6 +6056,7 @@ static void parse_record_options(int argc,
{"verbose", optional_argument, NULL, OPT_verbose},
{"compression", required_argument, NULL, OPT_compression},
{"file-version", required_argument, NULL, OPT_file_ver},
+ {"proxy", required_argument, NULL, OPT_proxy},
{NULL, 0, NULL, 0}
};
@@ -6060,7 +6072,8 @@ static void parse_record_options(int argc,
* If the current instance is to record a guest, then save
* all the arguments for this instance.
*/
- if (c != 'B' && c != 'A' && c != OPT_name && is_guest(ctx->instance)) {
+ if (c != 'B' && (c != 'A' || is_proxy) && c != OPT_name &&
+ is_guest(ctx->instance)) {
add_arg(ctx->instance, c, opts, long_options, optarg);
if (c == 'C')
ctx->instance->flags |= BUFFER_FL_HAS_CLOCK;
@@ -6132,12 +6145,16 @@ static void parse_record_options(int argc,
die("Failed to allocate name");
break;
+ case OPT_proxy:
+ is_proxy = true;
+ /* fall through */
case 'A': {
char *name = NULL;
int cid = -1, port = -1;
if (!IS_RECORD(ctx))
- die("-A is only allowed for record operations");
+ die("%s is only allowed for record operations",
+ is_proxy ? "--proxy" : "-A");
name = parse_guest_name(optarg, &cid, &port, &result);
if (cid == -1 && !result)
@@ -6164,6 +6181,9 @@ static void parse_record_options(int argc,
ctx->instance->port_type = USE_TCP;
}
+ if (is_proxy)
+ ctx->instance->flags |= BUFFER_FL_PROXY;
+
ctx->instance->flags |= BUFFER_FL_GUEST;
ctx->instance->result = result;
ctx->instance->cid = cid;
@@ -6386,6 +6406,8 @@ static void parse_record_options(int argc,
ctx->instance->buffer_size = atoi(optarg);
break;
case 'B':
+ /* Turn off proxy for the next options */
+ is_proxy = false;
ctx->instance = allocate_instance(optarg);
if (!ctx->instance)
die("Failed to create instance");
@@ -7033,6 +7055,7 @@ void trace_record(int argc, char **argv)
* @argv: The arguments to pass to the record session
* @use_fifos: True if fifos are used instead of sockets.
* @trace_id: The agent's trace_id
+ * @rcid: Remote cid if the agent is a proxy, negative otherwise.
* @host: Set if this is an IP connection and not a vsocket one
*
* This is used to enable tracing via the record command just
@@ -7044,8 +7067,7 @@ void trace_record(int argc, char **argv)
*/
int trace_record_agent(struct tracecmd_msg_handle *msg_handle,
int cpus, int *fds,
- int argc, char **argv,
- bool use_fifos,
+ int argc, char **argv, bool use_fifos,
unsigned long long trace_id, const char *host)
{
struct common_record_context ctx;