From 026a8516dce445ce5a6fa00fbd5e62118a5a8060 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Tue, 26 Apr 2022 16:49:38 -0400 Subject: [PATCH] Save/load: support session trace format Signed-off-by: Jonathan Rajotte Change-Id: I45d4e617a73f5b3c6d9cd56c03bdcc5cef05f36c --- include/lttng/trace-format-descriptor.h | 27 ++++ src/bin/lttng-sessiond/client.cpp | 10 ++ src/bin/lttng-sessiond/cmd.cpp | 130 ++++++++++++++- src/bin/lttng-sessiond/cmd.hpp | 3 + src/bin/lttng-sessiond/save.cpp | 5 + src/bin/lttng/commands/create.cpp | 81 +++++++++- src/bin/lttng/utils.cpp | 52 +++++- src/common/config/session-config.cpp | 101 ++++++++++-- src/common/relayd/relayd.cpp | 1 - src/common/session.xsd | 25 +++ src/common/sessiond-comm/relayd.hpp | 4 +- src/common/sessiond-comm/sessiond-comm.hpp | 9 ++ src/lib/lttng-ctl/liblttng-ctl.sym | 2 + src/lib/lttng-ctl/lttng-ctl.cpp | 179 +++++++++++++++++++++ 14 files changed, 603 insertions(+), 26 deletions(-) diff --git a/include/lttng/trace-format-descriptor.h b/include/lttng/trace-format-descriptor.h index ade822582..99cc94b04 100644 --- a/include/lttng/trace-format-descriptor.h +++ b/include/lttng/trace-format-descriptor.h @@ -9,6 +9,8 @@ #define LTTNG_TRACE_FORMAT_DESCRIPTOR_H #include +#include +#include #include #ifdef __cplusplus @@ -16,6 +18,7 @@ extern "C" { #endif struct lttng_trace_format_descriptor; +enum lttng_domain_type; enum lttng_trace_format_descriptor_status { LTTNG_TRACE_FORMAT_DESCRIPTOR_STATUS_INVALID = -1, @@ -49,6 +52,30 @@ LTTNG_EXPORT extern enum lttng_trace_format_descriptor_status lttng_trace_format LTTNG_EXPORT void lttng_trace_format_descriptor_destroy( struct lttng_trace_format_descriptor *descriptor); +/* + * Check if the passed trace format is supported for the passed domain. + */ +LTTNG_EXPORT extern enum lttng_error_code lttng_domain_supports_trace_format( + const struct lttng_endpoint *session_daemon_endpoint, + enum lttng_domain_type domain_type, + const struct lttng_trace_format_descriptor *trace_format_descriptor); + +/* + * For network destinations targeting a relay daemon, the session daemon will + * establish a connection to check for the capability at the time of the call. + * Note that the relay daemon at the destination address may be replaced by + * the time tracing starts. + * + * When destination url is a network destination (relayd), the following + * URL format is expected: + * NETPROTO://(HOST | IPADDR)[:CTRLPORT[:DATAPORT]][/TRACEPATH] + * + * Always returns LTTNG_OK for local destinations. + */ +LTTNG_EXPORT extern enum lttng_error_code lttng_destination_supports_trace_format( + const struct lttng_endpoint *session_daemon_endpoint, + const char *destination_url, + const struct lttng_trace_format_descriptor *trace_format_descriptor); #ifdef __cplusplus } diff --git a/src/bin/lttng-sessiond/client.cpp b/src/bin/lttng-sessiond/client.cpp index 3c4ea1b77..0aaf2c974 100644 --- a/src/bin/lttng-sessiond/client.cpp +++ b/src/bin/lttng-sessiond/client.cpp @@ -1009,6 +1009,9 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_EXECUTE_ERROR_QUERY: need_domain = false; break; + case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY: + need_domain = cmd_ctx->lsm.u.trace_format_support_query.query_type == 0; + break; default: need_domain = true; } @@ -1018,6 +1021,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_REGISTER_TRIGGER: case LTTNG_UNREGISTER_TRIGGER: case LTTNG_EXECUTE_ERROR_QUERY: + case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY: need_consumerd = false; break; default: @@ -1090,6 +1094,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_UNREGISTER_TRIGGER: case LTTNG_LIST_TRIGGERS: case LTTNG_EXECUTE_ERROR_QUERY: + case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY: need_tracing_session = false; break; default: @@ -2331,6 +2336,11 @@ skip_domain: break; } + case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY: + { + ret = cmd_execute_trace_format_support_query(*cmd_ctx, *sock, *sock_error); + break; + } default: ret = LTTNG_ERR_UND; break; diff --git a/src/bin/lttng-sessiond/cmd.cpp b/src/bin/lttng-sessiond/cmd.cpp index 214085c55..94edb6368 100644 --- a/src/bin/lttng-sessiond/cmd.cpp +++ b/src/bin/lttng-sessiond/cmd.cpp @@ -951,7 +951,9 @@ static lttng_error_code send_consumer_relayd_sockets(const ltt_session& session, consumer->relay_major_version = control_sock->major; consumer->relay_minor_version = control_sock->minor; - ret = relayd_get_configuration(control_sock, 0, result_flags, nullptr); + ret = relayd_get_configuration(control_sock, + LTTCOMM_RELAYD_CONFIGURATION_QUERY_FLAG_SUPPORTED_TRACE_FORMAT, + result_flags, &supported_trace_format); if (ret < 0) { ERR("Unable to get relayd configuration"); status = LTTNG_ERR_RELAYD_CONNECT_FAIL; @@ -6063,6 +6065,132 @@ end: return ret; } +enum lttng_error_code cmd_execute_trace_format_support_query( + struct command_ctx& cmd_ctx, int sock, int& sock_error) +{ + int ret; + enum lttng_error_code ret_code; + struct lttng_payload query_payload; + size_t payload_len, offset = 0; + ssize_t sock_recv_len, consumed; + + lttng::trace_format_descriptor::uptr trace_format; + + lttng_payload_init(&query_payload); + + /* Receive the payload */ + payload_len = (size_t) cmd_ctx.lsm.u.trace_format_support_query.trace_format_length + + cmd_ctx.lsm.u.trace_format_support_query.type_payload_length; + ret = lttng_dynamic_buffer_set_size(&query_payload.buffer, payload_len); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + } + + sock_recv_len = lttcomm_recv_unix_sock(sock, query_payload.buffer.data, payload_len); + if (sock_recv_len < 0 || sock_recv_len != payload_len) { + ERR("Failed to receive error query in command payload"); + sock_error = 1; + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + + /* Receive fds, if any. */ + if (cmd_ctx.lsm.fd_count > 0) { + sock_recv_len = lttcomm_recv_payload_fds_unix_sock( + sock, cmd_ctx.lsm.fd_count, &query_payload); + if (sock_recv_len > 0 && sock_recv_len != cmd_ctx.lsm.fd_count * sizeof(int)) { + ERR("Failed to receive all file descriptors for error query in command payload: expected fd count = %u, ret = %d", + cmd_ctx.lsm.fd_count, (int) ret); + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + sock_error = 1; + goto end; + } else if (sock_recv_len <= 0) { + ERR("Failed to receive file descriptors for error query in command payload: expected fd count = %u, ret = %d", + cmd_ctx.lsm.fd_count, (int) ret); + ret_code = LTTNG_ERR_FATAL; + sock_error = 1; + goto end; + } + } + + /* Deserialize trace_format_descriptor. */ + { + struct lttng_payload_view view = + lttng_payload_view_from_payload(&query_payload, offset, -1); + if (!lttng_payload_view_is_valid(&view)) { + ret = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + + consumed = lttng::trace_format_descriptor::create_from_payload(&view, trace_format); + + if (consumed != cmd_ctx.lsm.u.trace_format_support_query.trace_format_length) { + ERR("Invalid trace format descriptor received as part of command payload"); + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + offset += consumed; + } + + switch (cmd_ctx.lsm.u.trace_format_support_query.query_type) { + case 0: + { + if (cmd_ctx.lsm.domain.type != LTTNG_DOMAIN_KERNEL) { + /* UST supports all trace format*/ + ret_code = LTTNG_OK; + goto end; + } + ret_code = kernel_domain_check_trace_format_requirements(*trace_format); + break; + } + case 1: + { + struct lttcomm_relayd_sock *relay_sock = nullptr; + struct lttng_uri uri; + uint64_t result_flags = 0; + uint64_t supported_trace_format = 0; + struct lttng_payload_view view = lttng_payload_view_from_payload(&query_payload, + offset, + cmd_ctx.lsm.u.trace_format_support_query.type_payload_length); + if (!lttng_payload_view_is_valid(&view)) { + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + + memcpy(&uri, view.buffer.data, sizeof(uri)); + ret_code = create_connect_relayd(&uri, &relay_sock); + if (ret_code != LTTNG_OK) { + goto end; + } + LTTNG_ASSERT(sock); + + ret_code = relayd_get_configuration(relay_sock, + LTTCOMM_RELAYD_CONFIGURATION_QUERY_FLAG_SUPPORTED_TRACE_FORMAT, + result_flags, &supported_trace_format); + if (ret_code != LTTNG_OK) { + goto end; + } + + if (!(supported_trace_format & trace_format->relayd_type())) { + ERR("Relayd does not support the requested trace format"); + ret_code = LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_RELAY_DAEMON; + goto end; + } + + ret_code = LTTNG_OK; + break; + } + default: + { + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + break; + } + } +end: + lttng_payload_reset(&query_payload); + return ret_code; +} + /* Wait for a given path to be removed before continuing. */ static enum lttng_error_code wait_on_path(void *path_data) { diff --git a/src/bin/lttng-sessiond/cmd.hpp b/src/bin/lttng-sessiond/cmd.hpp index 4dd877be7..78d4f9cde 100644 --- a/src/bin/lttng-sessiond/cmd.hpp +++ b/src/bin/lttng-sessiond/cmd.hpp @@ -161,6 +161,9 @@ enum lttng_error_code cmd_execute_error_query(const struct lttng_credentials *cm struct lttng_error_query_results **_results, struct notification_thread_handle *notification_thread); +enum lttng_error_code cmd_execute_trace_format_support_query( + struct command_ctx& cmd_ctx, int sock, int& sock_error); + int cmd_rotate_session(struct ltt_session *session, struct lttng_rotate_session_return *rotate_return, bool quiet_rotation, diff --git a/src/bin/lttng-sessiond/save.cpp b/src/bin/lttng-sessiond/save.cpp index 5db70faef..825ad5413 100644 --- a/src/bin/lttng-sessiond/save.cpp +++ b/src/bin/lttng-sessiond/save.cpp @@ -2752,6 +2752,11 @@ int save_session(struct ltt_session *session, } } + ret = (int) session->trace_format->config_serialize(writer); + if (ret != LTTNG_OK) { + goto end; + } + ret = save_domains(writer, session); if (ret != LTTNG_OK) { goto end; diff --git a/src/bin/lttng/commands/create.cpp b/src/bin/lttng/commands/create.cpp index 68a1020a8..5841013d6 100644 --- a/src/bin/lttng/commands/create.cpp +++ b/src/bin/lttng/commands/create.cpp @@ -307,6 +307,7 @@ struct lttng_session_descriptor *create_session_descriptor(void) goto error; } } + end: free(uris); return descriptor; @@ -316,6 +317,77 @@ error: goto end; } +static int trace_format_check(struct lttng_session_descriptor& descriptor) +{ + int ret = 0; + enum lttng_error_code ret_code; + const lttng_trace_format_descriptor *trace_format_descriptor = nullptr; + enum lttng_session_descriptor_status status; + std::string destination; + + status = lttng_session_descriptor_get_trace_format_descriptor( + &descriptor, &trace_format_descriptor); + if (status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) { + ret_code = LTTNG_ERR_INVALID; + goto end; + } + + /* + * Only check kernel domain since only the kernel tracer can lag behind + * in term of feature. + */ + + ret_code = lttng_domain_supports_trace_format(lttng_session_daemon_command_endpoint, + LTTNG_DOMAIN_KERNEL, trace_format_descriptor); + if (ret_code == LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_KERNEL_TRACER) { + WARN("%s", lttng_strerror(ret_code)); + } else if (ret_code == LTTNG_ERR_KERN_NA || ret_code == LTTNG_ERR_NEED_ROOT_SESSIOND) { + /* + * Not an error, kernel tracers is simply not available at that + * time. Next operation will fail as necessary. + */ + DBG("Kernel tracer not available for trace format support check"); + } else if (ret_code != LTTNG_OK) { + ERR("Failed to validate trace format support: %s", lttng_strerror(ret_code)); + ret = -1; + goto end; + } + + if (opt_output_path) { + char *tmp = utils_expand_path(opt_output_path); + if (!tmp) { + ret = -1; + goto end; + } + destination = tmp; + free(tmp); + } else if (opt_url || opt_ctrl_url) { + destination = opt_ctrl_url ? opt_ctrl_url : opt_url; + } else if (opt_live_timer) { + destination = "tcp://127.0.0.1"; + } + + if (!destination.empty()) { + ret_code = lttng_destination_supports_trace_format( + lttng_session_daemon_command_endpoint, destination.c_str(), + trace_format_descriptor); + if (ret_code == LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_RELAY_DAEMON) { + WARN("%s", lttng_strerror(ret_code)); + } else if (ret_code == LTTNG_ERR_RELAYD_CONNECT_FAIL) { + DBG("Could not validate trace format support: %s", + lttng_strerror(ret_code)); + } else if (ret_code != LTTNG_OK) { + ERR("Failed to validate trace format support: %s", + lttng_strerror(ret_code)); + ret = -1; + goto end; + } + } + +end: + return ret; +} + /* * Create a tracing session. * If no name is specified, a default name is generated. @@ -375,6 +447,7 @@ static int create_session(void) ret = CMD_ERROR; goto error; } + ret_code = lttng_create_session_ext(session_descriptor); if (ret_code != LTTNG_OK) { ERR("%s", lttng_strerror(-ret_code)); @@ -382,8 +455,14 @@ static int create_session(void) goto error; } + ret = trace_format_check(*session_descriptor); + if (ret < 0) { + ret = CMD_ERROR; + goto error; + } + descriptor_status = lttng_session_descriptor_get_session_name( - session_descriptor, &created_session_name); + session_descriptor, &created_session_name); if (descriptor_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) { ERR("Failed to obtain created session name"); ret = CMD_ERROR; diff --git a/src/bin/lttng/utils.cpp b/src/bin/lttng/utils.cpp index 9a9f39bf2..fd839ecbf 100644 --- a/src/bin/lttng/utils.cpp +++ b/src/bin/lttng/utils.cpp @@ -6,15 +6,16 @@ */ #define _LGPL_SOURCE -#include +#include #include +#include #include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include +#include #include #include @@ -348,16 +349,51 @@ int spawn_relayd(const char *pathname, int port) * Spawn session daemon and tell * it to signal us when ready. */ - execlp(pathname, "lttng-relayd", "-L", url, NULL); + execlp(pathname, "lttng-relayd", "-L", url, "--daemonize", NULL); /* execlp only returns if error happened */ if (errno == ENOENT) { ERR("No relayd found. Use --relayd-path."); } else { PERROR("execlp"); } - kill(getppid(), SIGTERM); /* wake parent */ + kill(getppid(), SIGTERM); /* wake parent */ exit(EXIT_FAILURE); } else if (pid > 0) { + /* + * In daemon mode (--daemonize), lttng-relayd only exits when + * it's ready to accept commands. + */ + for (;;) { + int status; + pid_t wait_pid_ret = waitpid(pid, &status, 0); + + if (wait_pid_ret < 0) { + if (errno == EINTR) { + continue; + } + PERROR("waitpid"); + ret = -errno; + goto end; + } + + if (WIFSIGNALED(status)) { + ERR("Relay daemon was killed by signal %d", WTERMSIG(status)); + ret = -1; + goto end; + } else if (WIFEXITED(status)) { + DBG("Relay daemon terminated normally (exit status: %d)", + WEXITSTATUS(status)); + + if (WEXITSTATUS(status) != 0) { + ERR("Relay daemon terminated with an error (exit status: %d)", + WEXITSTATUS(status)); + ret = -1; + goto end; + } + break; + } + } + goto end; } else { PERROR("fork"); diff --git a/src/common/config/session-config.cpp b/src/common/config/session-config.cpp index f9d9d0eca..351c7f921 100644 --- a/src/common/config/session-config.cpp +++ b/src/common/config/session-config.cpp @@ -1154,9 +1154,10 @@ end: return ret; } -static -int create_snapshot_session(const char *session_name, xmlNodePtr output_node, - const struct config_load_session_override_attr *overrides) +static int create_snapshot_session(const char *session_name, + xmlNodePtr output_node, + const struct config_load_session_override_attr *overrides, + const struct lttng_trace_format_descriptor *trace_format_descriptor) { int ret; enum lttng_error_code ret_code; @@ -1178,6 +1179,16 @@ int create_snapshot_session(const char *session_name, xmlNodePtr output_node, goto end; } + if (trace_format_descriptor != nullptr) { + enum lttng_session_descriptor_status s_status; + s_status = lttng_session_descriptor_set_trace_format_descriptor( + session_descriptor, trace_format_descriptor); + if (s_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) { + ret = -LTTNG_ERR_FATAL; + goto end; + } + } + ret_code = lttng_create_session_ext(session_descriptor); if (ret_code != LTTNG_OK) { ret = -ret_code; @@ -1313,11 +1324,11 @@ end: return ret; } -static -int create_session(const char *name, - xmlNodePtr output_node, - uint64_t live_timer_interval, - const struct config_load_session_override_attr *overrides) +static int create_session(const char *name, + xmlNodePtr output_node, + uint64_t live_timer_interval, + const struct config_load_session_override_attr *overrides, + const struct lttng_trace_format_descriptor *trace_format_descriptor) { int ret = 0; enum lttng_error_code ret_code; @@ -1408,6 +1419,16 @@ int create_session(const char *name, goto end; } + if (trace_format_descriptor != nullptr) { + enum lttng_session_descriptor_status s_status; + s_status = lttng_session_descriptor_set_trace_format_descriptor( + session_descriptor, trace_format_descriptor); + if (s_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) { + ret = -LTTNG_ERR_FATAL; + goto end; + } + } + ret_code = lttng_create_session_ext(session_descriptor); if (ret_code != LTTNG_OK) { ret = -ret_code; @@ -3261,6 +3282,49 @@ end: return ret; } +/* TODO: this could most probably be moved to a similar scheme to create_from_buffer/payload for the + * lttng::trace_format_descriptor object */ +static int process_trace_format_descriptor_node(xmlNodePtr trace_format_descriptor_node, + struct lttng_trace_format_descriptor **descriptor) +{ + int ret; + xmlNodePtr node; + struct lttng_trace_format_descriptor *local_descriptor = nullptr; + struct lttng_trace_format_descriptor *(*constructor)(void) = nullptr; + + for (node = xmlFirstElementChild(trace_format_descriptor_node); node; + node = xmlNextElementSibling(node)) { + if (!strcmp((const char *) node->name, config_element_session_trace_format_ctf1)) { + constructor = lttng_trace_format_ctf_1_descriptor_create; + break; + } else if (!strcmp((const char *) node->name, + config_element_session_trace_format_ctf2)) { + constructor = lttng_trace_format_ctf_2_descriptor_create; + break; + } + } + + if (constructor == nullptr) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + local_descriptor = constructor(); + + if (local_descriptor == nullptr) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + *descriptor = local_descriptor; + local_descriptor = nullptr; + ret = 0; + +end: + lttng_trace_format_descriptor_destroy(local_descriptor); + return ret; +} + static int process_session_node(xmlNodePtr session_node, const char *session_name, int overwrite, @@ -3281,6 +3345,7 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, struct lttng_domain *jul_domain = NULL; struct lttng_domain *log4j_domain = NULL; struct lttng_domain *python_domain = NULL; + struct lttng_trace_format_descriptor *trace_format_descriptor = nullptr; for (node = xmlFirstElementChild(session_node); node; node = xmlNextElementSibling(node)) { @@ -3327,6 +3392,13 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, } shm_path = node_content; + } else if (!trace_format_descriptor && + !strcmp((const char *) node->name, + config_element_session_trace_format)) { + ret = process_trace_format_descriptor_node(node, &trace_format_descriptor); + if (ret) { + goto error; + } } else { /* * attributes, snapshot_mode, live_timer_interval, rotation_size, @@ -3482,16 +3554,16 @@ domain_init_error: /* Create session type depending on output type */ if (snapshot_mode && snapshot_mode != -1) { - ret = create_snapshot_session((const char *) name, output_node, - overrides); + ret = create_snapshot_session((const char *) name, output_node, overrides, + trace_format_descriptor); } else if (live_timer_interval && live_timer_interval != UINT64_MAX) { - ret = create_session((const char *) name, - output_node, live_timer_interval, overrides); + ret = create_session((const char *) name, output_node, live_timer_interval, + overrides, trace_format_descriptor); } else { /* regular session */ - ret = create_session((const char *) name, - output_node, UINT64_MAX, overrides); + ret = create_session((const char *) name, output_node, UINT64_MAX, overrides, + trace_format_descriptor); } if (ret) { goto error; @@ -3543,6 +3615,7 @@ end: } error: + lttng_trace_format_descriptor_destroy(trace_format_descriptor); free(kernel_domain); free(ust_domain); free(jul_domain); diff --git a/src/common/relayd/relayd.cpp b/src/common/relayd/relayd.cpp index 9f444d6e9..20a8aecba 100644 --- a/src/common/relayd/relayd.cpp +++ b/src/common/relayd/relayd.cpp @@ -103,7 +103,6 @@ static int send_command(struct lttcomm_relayd_sock *rsock, if (ret < 0) { PERROR("Failed to send command %s of size %" PRIu64, lttcomm_relayd_command_str(cmd), buf_size); - ret = rsock->sock.ops->sendmsg(&rsock->sock, buf, buf_size, flags); ret = -errno; goto error; } diff --git a/src/common/session.xsd b/src/common/session.xsd index 986fb2dda..4248f8e6b 100644 --- a/src/common/session.xsd +++ b/src/common/session.xsd @@ -512,6 +512,30 @@ by its signed 32-bit representation when converted to msec. + + + + + + + + + + + + + + + + + + + + + + + + @@ -520,6 +544,7 @@ by its signed 32-bit representation when converted to msec. + diff --git a/src/common/sessiond-comm/relayd.hpp b/src/common/sessiond-comm/relayd.hpp index 49d3ed1f7..d266284cb 100644 --- a/src/common/sessiond-comm/relayd.hpp +++ b/src/common/sessiond-comm/relayd.hpp @@ -20,7 +20,9 @@ #include #define RELAYD_VERSION_COMM_MAJOR VERSION_MAJOR -#define RELAYD_VERSION_COMM_MINOR VERSION_MINOR +/* FIXME: remove, SPOOFING VERSION as 2.15 */ +//#define RELAYD_VERSION_COMM_MINOR VERSION_MINOR +#define RELAYD_VERSION_COMM_MINOR 15 #define RELAYD_COMM_LTTNG_HOST_NAME_MAX_2_4 64 #define RELAYD_COMM_LTTNG_NAME_MAX_2_4 255 diff --git a/src/common/sessiond-comm/sessiond-comm.hpp b/src/common/sessiond-comm/sessiond-comm.hpp index f5e55ec34..2ef654476 100644 --- a/src/common/sessiond-comm/sessiond-comm.hpp +++ b/src/common/sessiond-comm/sessiond-comm.hpp @@ -103,6 +103,7 @@ enum lttcomm_sessiond_command { LTTNG_CLEAR_SESSION = 50, LTTNG_LIST_TRIGGERS = 51, LTTNG_EXECUTE_ERROR_QUERY = 52, + LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY = 53, }; static inline @@ -195,6 +196,8 @@ const char *lttcomm_sessiond_command_str(enum lttcomm_sessiond_command cmd) return "LTTNG_LIST_TRIGGERS"; case LTTNG_EXECUTE_ERROR_QUERY: return "LTTNG_EXECUTE_ERROR_QUERY"; + case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY: + return "LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY"; default: abort(); } @@ -535,6 +538,12 @@ struct lttcomm_session_msg { uint64_t session_descriptor_size; /* An lttng_session_descriptor follows. */ } LTTNG_PACKED create_session; + struct { + uint32_t query_type; + uint32_t type_payload_length; + uint32_t trace_format_length; + } LTTNG_PACKED trace_format_support_query; + } u; /* Count of fds sent. */ uint32_t fd_count; diff --git a/src/lib/lttng-ctl/liblttng-ctl.sym b/src/lib/lttng-ctl/liblttng-ctl.sym index 1866c4801..5bd03fdcf 100644 --- a/src/lib/lttng-ctl/liblttng-ctl.sym +++ b/src/lib/lttng-ctl/liblttng-ctl.sym @@ -192,6 +192,7 @@ lttng_create_session_ext lttng_create_session_live lttng_create_session_snapshot lttng_data_pending +lttng_destination_supports_trace_format lttng_destroy_handle lttng_destroy_session lttng_destroy_session_ext @@ -205,6 +206,7 @@ lttng_disable_channel lttng_disable_consumer lttng_disable_event lttng_disable_event_ext +lttng_domain_supports_trace_format lttng_elf_get_sdt_probe_offsets lttng_elf_get_symbol_offset lttng_enable_channel diff --git a/src/lib/lttng-ctl/lttng-ctl.cpp b/src/lib/lttng-ctl/lttng-ctl.cpp index c6b2e2f35..5c7dc917b 100644 --- a/src/lib/lttng-ctl/lttng-ctl.cpp +++ b/src/lib/lttng-ctl/lttng-ctl.cpp @@ -3441,3 +3441,182 @@ static void __attribute__((destructor)) lttng_ctl_exit(void) { free(tracing_group); } + +LTTNG_EXPORT enum lttng_error_code lttng_domain_supports_trace_format( + const struct lttng_endpoint *session_daemon_endpoint, + enum lttng_domain_type domain_type, + const struct lttng_trace_format_descriptor *trace_format_descriptor) +{ + int ret; + enum lttng_error_code ret_code; + struct lttcomm_session_msg lsm = { + .cmd_type = LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY, + .session = {}, + .domain = {}, + .u = {}, + .fd_count = 0, + }; + struct lttng_payload message; + struct lttng_payload reply; + struct lttcomm_session_msg *message_lsm; + + lttng_payload_init(&message); + lttng_payload_init(&reply); + + if (!session_daemon_endpoint || !trace_format_descriptor) { + ret_code = LTTNG_ERR_INVALID; + goto end; + } + + lsm.domain.type = domain_type; + lsm.u.trace_format_support_query.query_type = 0; + lsm.u.trace_format_support_query.type_payload_length = 0; + + if (session_daemon_endpoint != lttng_session_daemon_command_endpoint) { + ret_code = LTTNG_ERR_INVALID_ERROR_QUERY_TARGET; + goto end; + } + + ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + ret = reinterpret_cast(trace_format_descriptor) + ->serialize(&message); + if (ret) { + ret_code = LTTNG_ERR_UNK; + goto end; + } + + message_lsm = (struct lttcomm_session_msg *) message.buffer.data; + message_lsm->u.trace_format_support_query.trace_format_length = + (uint32_t) message.buffer.size - sizeof(lsm); + + { + struct lttng_payload_view message_view = + lttng_payload_view_from_payload(&message, 0, -1); + + message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(&message_view); + ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply); + if (ret < 0) { + ret_code = (lttng_error_code) -ret; + goto end; + } + if (ret != 0) { + /* No payload expected */ + ret = LTTNG_ERR_INVALID_PROTOCOL; + } + } + + ret_code = LTTNG_OK; +end: + lttng_payload_reset(&message); + lttng_payload_reset(&reply); + return ret_code; +} + +LTTNG_EXPORT extern enum lttng_error_code lttng_destination_supports_trace_format( + const struct lttng_endpoint *session_daemon_endpoint, + const char *destination_url, + const struct lttng_trace_format_descriptor *trace_format_descriptor) +{ + int ret; + ssize_t size; + enum lttng_error_code ret_code; + struct lttcomm_session_msg lsm = { + .cmd_type = LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY, + .session = {}, + .domain = {}, + .u = {}, + .fd_count = 0, + }; + struct lttng_payload message; + struct lttng_payload reply; + struct lttcomm_session_msg *message_lsm; + struct lttng_uri *uris = NULL; + size_t size_before_payload = 0; + + lttng_payload_init(&message); + lttng_payload_init(&reply); + + if (!session_daemon_endpoint || !trace_format_descriptor) { + ret_code = LTTNG_ERR_INVALID; + goto end; + } + + size = uri_parse_str_urls(destination_url, NULL, &uris); + if (size < 1) { + ret_code = LTTNG_ERR_INVALID; + goto end; + } + + if (uris[0].dtype == LTTNG_DST_PATH) { + /* Local output */ + ret_code = LTTNG_OK; + goto end; + } + + lsm.u.trace_format_support_query.query_type = 1; + + if (session_daemon_endpoint != lttng_session_daemon_command_endpoint) { + ret_code = LTTNG_ERR_INVALID_ERROR_QUERY_TARGET; + goto end; + } + + ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + size_before_payload = message.buffer.size; + + ret = reinterpret_cast(trace_format_descriptor) + ->serialize(&message); + if (ret) { + ret_code = LTTNG_ERR_UNK; + goto end; + } + + message_lsm = (struct lttcomm_session_msg *) message.buffer.data; + message_lsm->u.trace_format_support_query.trace_format_length = + (uint32_t) message.buffer.size - size_before_payload; + + /* FIXME replace all this with good old serialization of sub query type + * object. (internal) */ + size_before_payload = message.buffer.size; + ret = lttng_dynamic_buffer_append(&message.buffer, &uris[0], sizeof(*uris)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + message_lsm = (struct lttcomm_session_msg *) message.buffer.data; + message_lsm->u.trace_format_support_query.type_payload_length = + (uint32_t) message.buffer.size - size_before_payload; + + { + struct lttng_payload_view message_view = + lttng_payload_view_from_payload(&message, 0, -1); + + message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(&message_view); + ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply); + if (ret < 0) { + ret_code = (lttng_error_code) -ret; + goto end; + } + if (ret != 0) { + /* No payload expected */ + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + } + + ret_code = LTTNG_OK; +end: + lttng_payload_reset(&message); + lttng_payload_reset(&reply); + return ret_code; +} -- 2.34.1