| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "windows_plugin.h" |
| 4 | #include "windows-internals.h" |
| 5 | |
| 6 | struct smb_share { |
| 7 | usec_t last_collected; |
| 8 | |
| 9 | RRDSET *st_current_open_file_count; |
| 10 | RRDSET *st_tree_connect_count; |
| 11 | RRDSET *st_received_bytes; |
| 12 | RRDSET *st_write_requests; |
| 13 | RRDSET *st_read_requests; |
| 14 | RRDSET *st_metadata_requests; |
| 15 | RRDSET *st_sent_bytes; |
| 16 | RRDSET *st_files_opened; |
| 17 | |
| 18 | RRDDIM *rd_current_open_file_count; |
| 19 | RRDDIM *rd_tree_connect_count; |
| 20 | RRDDIM *rd_received_bytes; |
| 21 | RRDDIM *rd_write_requests; |
| 22 | RRDDIM *rd_read_requests; |
| 23 | RRDDIM *rd_metadata_requests; |
| 24 | RRDDIM *rd_sent_bytes; |
| 25 | RRDDIM *rd_files_opened; |
| 26 | |
| 27 | COUNTER_DATA currentOpenFileCount; |
| 28 | COUNTER_DATA treeConnectCount; |
| 29 | COUNTER_DATA receivedBytes; |
| 30 | COUNTER_DATA writeRequests; |
| 31 | COUNTER_DATA readRequests; |
| 32 | COUNTER_DATA metadataRequests; |
| 33 | COUNTER_DATA sentBytes; |
| 34 | COUNTER_DATA filesOpened; |
| 35 | }; |
| 36 | |
| 37 | static DICTIONARY *smb_shares = NULL; |
| 38 | |
| 39 | static void smb_share_initialize(struct smb_share *share) |
| 40 | { |
| 41 | share->currentOpenFileCount.key = "Current Open File Count"; |
| 42 | share->treeConnectCount.key = "Tree Connect Count"; |
| 43 | share->receivedBytes.key = "Received Bytes/sec"; |
| 44 | share->writeRequests.key = "Write Requests/sec"; |
| 45 | share->readRequests.key = "Read Requests/sec"; |
| 46 | share->metadataRequests.key = "Metadata Requests/sec"; |
| 47 | share->sentBytes.key = "Sent Bytes/sec"; |
| 48 | share->filesOpened.key = "Files Opened/sec"; |
| 49 | } |
| 50 | |
| 51 | static void smb_share_cleanup(struct smb_share *share) |
| 52 | { |
| 53 | rrdset_is_obsolete___safe_from_collector_thread(share->st_current_open_file_count); |
| 54 | rrdset_is_obsolete___safe_from_collector_thread(share->st_tree_connect_count); |
| 55 | rrdset_is_obsolete___safe_from_collector_thread(share->st_received_bytes); |
| 56 | rrdset_is_obsolete___safe_from_collector_thread(share->st_write_requests); |
| 57 | rrdset_is_obsolete___safe_from_collector_thread(share->st_read_requests); |
| 58 | rrdset_is_obsolete___safe_from_collector_thread(share->st_metadata_requests); |
| 59 | rrdset_is_obsolete___safe_from_collector_thread(share->st_sent_bytes); |
| 60 | rrdset_is_obsolete___safe_from_collector_thread(share->st_files_opened); |
| 61 | } |
| 62 | |
| 63 | static void dict_smb_share_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) |
| 64 | { |
| 65 | struct smb_share *share = value; |
| 66 | |
| 67 | smb_share_initialize(share); |
| 68 | } |
| 69 | |
| 70 | static void dict_smb_share_delete_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) |
| 71 | { |
| 72 | struct smb_share *share = value; |
| 73 | |
| 74 | smb_share_cleanup(share); |
| 75 | } |
| 76 | |
| 77 | static void initialize(void) |
| 78 | { |
| 79 | smb_shares = dictionary_create_advanced( |
| 80 | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct smb_share)); |
| 81 | |
| 82 | dictionary_register_insert_callback(smb_shares, dict_smb_share_insert_cb, NULL); |
| 83 | dictionary_register_delete_callback(smb_shares, dict_smb_share_delete_cb, NULL); |
| 84 | } |
| 85 | |
| 86 | static void smb_share_chart( |
| 87 | RRDSET **st, |
| 88 | RRDDIM **rd, |
| 89 | COUNTER_DATA *counter, |
| 90 | int update_every, |
| 91 | const char *share, |
| 92 | const char *id_suffix, |
| 93 | const char *context, |
| 94 | const char *title, |
| 95 | const char *units, |
| 96 | int priority, |
| 97 | const char *dimension) |
| 98 | { |
| 99 | if (!counter->updated) |
| 100 | return; |
| 101 | |
| 102 | if (unlikely(!*st)) { |
| 103 | char id[RRD_ID_LENGTH_MAX + 1]; |
| 104 | snprintfz(id, sizeof(id), "smb_share_%s_%s", share, id_suffix); |
| 105 | netdata_fix_chart_name(id); |
| 106 | |
| 107 | *st = rrdset_create_localhost( |
| 108 | "smb", |
| 109 | id, |
| 110 | NULL, |
| 111 | "shares", |
| 112 | context, |
| 113 | title, |
| 114 | units, |
| 115 | PLUGIN_WINDOWS_NAME, |
| 116 | "PerflibSMB", |
| 117 | priority, |
| 118 | update_every, |
| 119 | RRDSET_TYPE_LINE); |
| 120 | |
| 121 | *rd = perflib_rrddim_add(*st, dimension, NULL, 1, 1, counter); |
| 122 | rrdlabels_add((*st)->rrdlabels, "share", share, RRDLABEL_SRC_AUTO); |
| 123 | } |
| 124 | |
| 125 | perflib_rrddim_set_by_pointer(*st, *rd, counter); |
| 126 | rrdset_done(*st); |
| 127 | } |
| 128 | |
| 129 | static bool do_smb_server_shares(PERF_DATA_BLOCK *pDataBlock, int update_every) |
| 130 | { |
| 131 | PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "SMB Server Shares"); |
| 132 | if (!pObjectType) |
| 133 | return false; |
| 134 | |
| 135 | usec_t now_ut = now_monotonic_usec(); |
| 136 | |
| 137 | PERF_INSTANCE_DEFINITION *pi = NULL; |
| 138 | for (LONG i = 0; i < pObjectType->NumInstances; i++) { |
| 139 | pi = perflibForEachInstance(pDataBlock, pObjectType, pi); |
| 140 | if (!pi) |
| 141 | break; |
| 142 | |
| 143 | if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer))) |
| 144 | strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1); |
| 145 | |
| 146 | struct smb_share *share = dictionary_set(smb_shares, windows_shared_buffer, NULL, sizeof(*share)); |
| 147 | share->last_collected = now_ut; |
| 148 | |
| 149 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->currentOpenFileCount); |
| 150 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->treeConnectCount); |
| 151 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->receivedBytes); |
| 152 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->writeRequests); |
| 153 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->readRequests); |
| 154 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->metadataRequests); |
| 155 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->sentBytes); |
| 156 | perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &share->filesOpened); |
| 157 | |
| 158 | smb_share_chart( |
| 159 | &share->st_current_open_file_count, |
| 160 | &share->rd_current_open_file_count, |
| 161 | &share->currentOpenFileCount, |
| 162 | update_every, |
| 163 | windows_shared_buffer, |
| 164 | "current_open_file_count", |
| 165 | "smb.server_shares_current_open_file_count", |
| 166 | "Current open file count on the SMB share", |
| 167 | "files", |
| 168 | PRIO_SMB_SERVER_SHARES_CURRENT_OPEN_FILE_COUNT, |
| 169 | "open"); |
| 170 | |
| 171 | smb_share_chart( |
| 172 | &share->st_tree_connect_count, |
| 173 | &share->rd_tree_connect_count, |
| 174 | &share->treeConnectCount, |
| 175 | update_every, |
| 176 | windows_shared_buffer, |
| 177 | "tree_connect_count", |
| 178 | "smb.server_shares_tree_connect_count", |
| 179 | "Tree connect count on the SMB share", |
| 180 | "connections", |
| 181 | PRIO_SMB_SERVER_SHARES_TREE_CONNECT_COUNT, |
| 182 | "connections"); |
| 183 | |
| 184 | smb_share_chart( |
| 185 | &share->st_received_bytes, |
| 186 | &share->rd_received_bytes, |
| 187 | &share->receivedBytes, |
| 188 | update_every, |
| 189 | windows_shared_buffer, |
| 190 | "received_bytes", |
| 191 | "smb.server_shares_received_bytes", |
| 192 | "Received bytes on the SMB share", |
| 193 | "bytes/s", |
| 194 | PRIO_SMB_SERVER_SHARES_RECEIVED_BYTES, |
| 195 | "received"); |
| 196 | |
| 197 | smb_share_chart( |
| 198 | &share->st_write_requests, |
| 199 | &share->rd_write_requests, |
| 200 | &share->writeRequests, |
| 201 | update_every, |
| 202 | windows_shared_buffer, |
| 203 | "write_requests", |
| 204 | "smb.server_shares_write_requests", |
| 205 | "Write requests on the SMB share", |
| 206 | "requests/s", |
| 207 | PRIO_SMB_SERVER_SHARES_WRITE_REQUESTS, |
| 208 | "writes"); |
| 209 | |
| 210 | smb_share_chart( |
| 211 | &share->st_read_requests, |
| 212 | &share->rd_read_requests, |
| 213 | &share->readRequests, |
| 214 | update_every, |
| 215 | windows_shared_buffer, |
| 216 | "read_requests", |
| 217 | "smb.server_shares_read_requests", |
| 218 | "Read requests on the SMB share", |
| 219 | "requests/s", |
| 220 | PRIO_SMB_SERVER_SHARES_READ_REQUESTS, |
| 221 | "reads"); |
| 222 | |
| 223 | smb_share_chart( |
| 224 | &share->st_metadata_requests, |
| 225 | &share->rd_metadata_requests, |
| 226 | &share->metadataRequests, |
| 227 | update_every, |
| 228 | windows_shared_buffer, |
| 229 | "metadata_requests", |
| 230 | "smb.server_shares_metadata_requests", |
| 231 | "Metadata requests on the SMB share", |
| 232 | "requests/s", |
| 233 | PRIO_SMB_SERVER_SHARES_METADATA_REQUESTS, |
| 234 | "metadata"); |
| 235 | |
| 236 | smb_share_chart( |
| 237 | &share->st_sent_bytes, |
| 238 | &share->rd_sent_bytes, |
| 239 | &share->sentBytes, |
| 240 | update_every, |
| 241 | windows_shared_buffer, |
| 242 | "sent_bytes", |
| 243 | "smb.server_shares_sent_bytes", |
| 244 | "Sent bytes on the SMB share", |
| 245 | "bytes/s", |
| 246 | PRIO_SMB_SERVER_SHARES_SENT_BYTES, |
| 247 | "sent"); |
| 248 | |
| 249 | smb_share_chart( |
| 250 | &share->st_files_opened, |
| 251 | &share->rd_files_opened, |
| 252 | &share->filesOpened, |
| 253 | update_every, |
| 254 | windows_shared_buffer, |
| 255 | "files_opened", |
| 256 | "smb.server_shares_files_opened", |
| 257 | "Files opened on the SMB share", |
| 258 | "files/s", |
| 259 | PRIO_SMB_SERVER_SHARES_FILES_OPENED, |
| 260 | "opened"); |
| 261 | } |
| 262 | |
| 263 | // delete entries not seen in this collection cycle |
| 264 | { |
| 265 | struct smb_share *share; |
| 266 | dfe_start_write(smb_shares, share) |
| 267 | { |
| 268 | if (share->last_collected < now_ut) |
| 269 | dictionary_del(smb_shares, share_dfe.name); |
| 270 | } |
| 271 | dfe_done(share); |
| 272 | dictionary_garbage_collect(smb_shares); |
| 273 | } |
| 274 | |
| 275 | return true; |
| 276 | } |
| 277 | |
| 278 | void do_PerflibSMB_cleanup(void) |
| 279 | { |
| 280 | dictionary_destroy(smb_shares); |
| 281 | smb_shares = NULL; |
| 282 | } |
| 283 | |
| 284 | int do_PerflibSMB(int update_every, usec_t dt __maybe_unused) |
| 285 | { |
| 286 | static bool initialized = false; |
| 287 | |
| 288 | if (unlikely(!initialized)) { |
| 289 | initialize(); |
| 290 | initialized = true; |
| 291 | } |
| 292 | |
| 293 | DWORD id = RegistryFindIDByName("SMB Server Shares"); |
| 294 | if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND) |
| 295 | return -1; |
| 296 | |
| 297 | PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id); |
| 298 | if (!pDataBlock) |
| 299 | return -1; |
| 300 | |
| 301 | do_smb_server_shares(pDataBlock, update_every); |
| 302 | |
| 303 | return 0; |
| 304 | } |