#include "replace.h"
#include <tdb.h>
#include "lib/util/time.h"
+#include "libcli/smb/smb2_constants.h"
+#include "libcli/util/ntstatus.h"
struct smbd_server_connection;
struct tevent_context;
struct smbprofile_stats_iobytes {
uint64_t count; /* number of events */
+ uint64_t failed_count; /* number of unsuccessful events */
uint64_t time; /* microseconds */
uint64_t buckets[10]; /* 1,2,4,...256,Inf msecs */
uint64_t idle; /* idle time compared to 'time' microseconds */
_SMBPROFILE_TIMER_ASYNC_SET_IDLE(_async)
#define SMBPROFILE_IOBYTES_ASYNC_SET_BUSY(_async) \
_SMBPROFILE_TIMER_ASYNC_SET_BUSY(_async)
-#define SMBPROFILE_IOBYTES_ASYNC_END(_async, _outbytes) do { \
+#define SMBPROFILE_IOBYTES_ASYNC_END(_async, _outbytes, _opcode, _status) do { \
if ((_async).stats != NULL) { \
(_async).stats->outbytes += (_outbytes); \
_SMBPROFILE_TIMER_ASYNC_END(_async); \
+ smbprofile_update_failed_count((_async.stats), (_opcode), (_status)); \
smbprofile_update_hist((_async).stats, profile_timestamp() - (_async).start); \
(_async) = (struct smbprofile_stats_iobytes_async) {}; \
smbprofile_dump_schedule(); \
return smbprofile_state.config.do_count;
}
+static inline void smbprofile_update_failed_count(
+ struct smbprofile_stats_iobytes *s,
+ uint16_t opcode,
+ NTSTATUS status)
+{
+ bool ok = NT_STATUS_IS_OK(status);
+
+ switch (opcode) {
+ case SMB2_OP_SESSSETUP:
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ ok = true;
+ }
+ break;
+ case SMB2_OP_QUERY_DIRECTORY:
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
+ ok = true;
+ }
+ break;
+ case SMB2_OP_NOTIFY:
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) {
+ ok = true;
+ }
+ break;
+ }
+
+ if (!ok) {
+ s->failed_count += 1;
+ }
+}
+
static inline void smbprofile_update_hist(struct smbprofile_stats_iobytes *s,
uint64_t microsecs)
{
#define SMBPROFILE_IOBYTES_ASYNC_START(_name, _area, _async, _inbytes)
#define SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(_async)
#define SMBPROFILE_IOBYTES_ASYNC_SET_BUSY(_async)
-#define SMBPROFILE_IOBYTES_ASYNC_END(_async, _outbytes)
+#define SMBPROFILE_IOBYTES_ASYNC_END(_async, _outbytes, _opcode, _status)
#define DO_PROFILE_INC(x)
#define START_PROFILE(x)
do { \
acc->values.name##_stats.count += \
add->values.name##_stats.count; \
+ acc->values.name##_stats.failed_count += \
+ add->values.name##_stats.failed_count; \
acc->values.name##_stats.time += \
add->values.name##_stats.time; \
acc->values.name##_stats.buckets[0] += \
SMBPROFILE_IOBYTES_ASYNC_START(smb2_cancel, profile_p,
req->profile, _INBYTES(req));
return_value = smbd_smb2_request_process_cancel(req);
- SMBPROFILE_IOBYTES_ASYNC_END(req->profile, 0);
+ SMBPROFILE_IOBYTES_ASYNC_END(req->profile,
+ 0,
+ SMB2_OP_CANCEL,
+ NT_STATUS_OK);
/*
* We don't need the request anymore cancel requests never
}
TALLOC_FREE(req->last_sign_key);
- SMBPROFILE_IOBYTES_ASYNC_END(req->profile,
- iov_buflen(outhdr, SMBD_SMB2_NUM_IOV_PER_REQ-1));
+ SMBPROFILE_IOBYTES_ASYNC_END(
+ req->profile,
+ iov_buflen(outhdr, SMBD_SMB2_NUM_IOV_PER_REQ - 1),
+ PULL_LE_U16(outhdr->iov_base, SMB2_HDR_OPCODE),
+ NT_STATUS(IVAL(outhdr->iov_base, SMB2_HDR_STATUS)));
req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
struct evbuffer *buf;
bool sent_help_cpu_seconds : 1;
bool sent_help_smb1_request_total : 1;
- bool sent_help_smb2_request_total : 1;
bool sent_help_smb2_request_inbytes : 1;
bool sent_help_smb2_request_outbytes : 1;
bool sent_help_smb2_request_hist : 1;
+ bool sent_help_smb2_request_failed : 1;
};
static void export_count(const char *name,
}
}
+static void export_iobytes_failed(const char *name,
+ const struct smbprofile_stats_iobytes *val,
+ struct export_state *state)
+{
+ bool is_smb2;
+
+ is_smb2 = (strncmp(name, "smb2_", 5) == 0);
+ if (is_smb2) {
+ if (!state->sent_help_smb2_request_failed) {
+ evbuffer_add_printf(
+ state->buf,
+ "# HELP smb_smb2_request_failed Number "
+ "of failed SMB2 requests\n"
+ "# TYPE smb_smb2_request_failed counter\n");
+ state->sent_help_smb2_request_failed = true;
+ }
+
+ evbuffer_add_printf(
+ state->buf,
+ "smb_smb2_request_failed { operation=\"%s\" } "
+ "%" PRIu64 "\n",
+ name + 5,
+ val->failed_count);
+ }
+}
+
static void metrics_handler(struct evhttp_request *req, void *arg)
{
struct export_state state = {.buf = NULL};
#undef SMBPROFILE_STATS_BYTES
#undef SMBPROFILE_STATS_IOBYTES
#undef SMBPROFILE_STATS_SECTION_END
+#undef SMBPROFILE_STATS_END
+
+#define SMBPROFILE_STATS_START
+#define SMBPROFILE_STATS_SECTION_START(name, display)
+#define SMBPROFILE_STATS_COUNT(name)
+#define SMBPROFILE_STATS_TIME(name)
+#define SMBPROFILE_STATS_BASIC(name)
+#define SMBPROFILE_STATS_BYTES(name)
+#define SMBPROFILE_STATS_IOBYTES(name) \
+ do { \
+ export_iobytes_failed(#name, \
+ &stats.values.name##_stats, \
+ &state); \
+ } while (0);
+#define SMBPROFILE_STATS_SECTION_END
+#define SMBPROFILE_STATS_END
+ SMBPROFILE_STATS_ALL_SECTIONS
+#undef SMBPROFILE_STATS_START
+#undef SMBPROFILE_STATS_SECTION_START
+#undef SMBPROFILE_STATS_COUNT
+#undef SMBPROFILE_STATS_TIME
+#undef SMBPROFILE_STATS_BASIC
+#undef SMBPROFILE_STATS_BYTES
+#undef SMBPROFILE_STATS_IOBYTES
+#undef SMBPROFILE_STATS_SECTION_END
#undef SMBPROFILE_STATS_END
evhttp_send_reply(req, HTTP_OK, "OK", state.buf);
} while(0);
#define SMBPROFILE_STATS_IOBYTES(name) do { \
__PRINT_FIELD_LINE(#name, name##_stats, count); \
+ __PRINT_FIELD_LINE(#name, name##_stats, failed_count); \
__PRINT_FIELD_LINE(#name, name##_stats, time); \
print_buckets(state, #name, &stats.values.name##_stats); \
__PRINT_FIELD_LINE(#name, name##_stats, idle); \