master
c 1,060 lines 38.8 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4
5 #include <xenstat.h>
6 #include <libxl.h>
7
8 #define PLUGIN_XENSTAT_NAME "xenstat.plugin"
9
10 #define NETDATA_CHART_PRIO_XENSTAT_NODE_CPUS 30001
11 #define NETDATA_CHART_PRIO_XENSTAT_NODE_CPU_FREQ 30002
12 #define NETDATA_CHART_PRIO_XENSTAT_NODE_MEM 30003
13 #define NETDATA_CHART_PRIO_XENSTAT_NODE_TMEM 30004
14 #define NETDATA_CHART_PRIO_XENSTAT_NODE_DOMAINS 30005
15
16 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_STATES 30101
17 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_CPU 30102
18 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VCPU 30103
19 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_MEM 30104
20
21 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_TMEM_PAGES 30104
22 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_TMEM_OPERATIONS 30105
23
24 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_OO_REQ 30200
25 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_REQUESTS 30300
26 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_SECTORS 30400
27
28 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_BYTES 30500
29 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS 30600
30 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_ERRORS 30700
31 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_DROPS 30800
32
33 #define TYPE_LENGTH_MAX 200
34
35 #define CHART_IS_OBSOLETE 1
36 #define CHART_IS_NOT_OBSOLETE 0
37
38 // Variables
39 static int debug = 0;
40 static int netdata_update_every = 1;
41
42 struct vcpu_metrics {
43 unsigned int id;
44
45 unsigned int online;
46 unsigned long long ns;
47
48 int chart_generated;
49 int updated;
50
51 struct vcpu_metrics *next;
52 };
53
54 struct vbd_metrics {
55 unsigned int id;
56
57 unsigned int error;
58 unsigned long long oo_reqs;
59 unsigned long long rd_reqs;
60 unsigned long long wr_reqs;
61 unsigned long long rd_sects;
62 unsigned long long wr_sects;
63
64 int oo_req_chart_generated;
65 int requests_chart_generated;
66 int sectors_chart_generated;
67 int updated;
68
69 struct vbd_metrics *next;
70 };
71
72 struct network_metrics {
73 unsigned int id;
74
75 unsigned long long rbytes;
76 unsigned long long rpackets;
77 unsigned long long rerrs;
78 unsigned long long rdrops;
79
80 unsigned long long tbytes;
81 unsigned long long tpackets;
82 unsigned long long terrs;
83 unsigned long long tdrops;
84
85 int bytes_chart_generated;
86 int packets_chart_generated;
87 int errors_chart_generated;
88 int drops_chart_generated;
89 int updated;
90
91 struct network_metrics *next;
92 };
93
94 struct domain_metrics {
95 char *uuid;
96 uint32_t hash;
97
98 unsigned int id;
99 char *name;
100
101 // states
102 unsigned int running;
103 unsigned int blocked;
104 unsigned int paused;
105 unsigned int shutdown;
106 unsigned int crashed;
107 unsigned int dying;
108 unsigned int cur_vcpus;
109
110 unsigned long long cpu_ns;
111 unsigned long long cur_mem;
112 unsigned long long max_mem;
113
114 struct vcpu_metrics *vcpu_root;
115 struct vbd_metrics *vbd_root;
116 struct network_metrics *network_root;
117
118 int states_chart_generated;
119 int cpu_chart_generated;
120 int vcpu_chart_generated;
121 int num_vcpus_changed;
122 int mem_chart_generated;
123 int updated;
124
125 struct domain_metrics *next;
126 };
127
128 struct node_metrics{
129 unsigned long long tot_mem;
130 unsigned long long free_mem;
131 int num_domains;
132 unsigned int num_cpus;
133 unsigned long long node_cpu_hz;
134
135 struct domain_metrics *domain_root;
136 };
137
138 static struct node_metrics node_metrics = {
139 .domain_root = NULL
140 };
141
142 static inline struct domain_metrics *domain_metrics_get(const char *uuid, uint32_t hash) {
143 struct domain_metrics *d = NULL, *last = NULL;
144 for(d = node_metrics.domain_root; d ; last = d, d = d->next) {
145 if(unlikely(d->hash == hash && !strcmp(d->uuid, uuid)))
146 return d;
147 }
148
149 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: allocating memory for domain with uuid %s\n", uuid);
150
151 d = callocz(1, sizeof(struct domain_metrics));
152 d->uuid = strdupz(uuid);
153 d->hash = hash;
154
155 if(unlikely(!last)) {
156 d->next = node_metrics.domain_root;
157 node_metrics.domain_root = d;
158 }
159 else {
160 d->next = last->next;
161 last->next = d;
162 }
163
164 return d;
165 }
166
167 static struct domain_metrics *domain_metrics_free(struct domain_metrics *d) {
168 struct domain_metrics *cur = NULL, *last = NULL;
169 struct vcpu_metrics *vcpu, *vcpu_f;
170 struct vbd_metrics *vbd, *vbd_f;
171 struct network_metrics *network, *network_f;
172
173 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: freeing memory for domain '%s' id %u, uuid %s\n", d->name, d->id, d->uuid);
174
175 for(cur = node_metrics.domain_root; cur ; last = cur, cur = cur->next) {
176 if(unlikely(cur->hash == d->hash && !strcmp(cur->uuid, d->uuid))) break;
177 }
178
179 if(unlikely(!cur)) {
180 netdata_log_error("XENSTAT: failed to free domain metrics.");
181 return NULL;
182 }
183
184 if(likely(last))
185 last->next = cur->next;
186 else
187 node_metrics.domain_root = NULL;
188
189 freez(cur->uuid);
190 freez(cur->name);
191
192 vcpu = cur->vcpu_root;
193 while(vcpu) {
194 vcpu_f = vcpu;
195 vcpu = vcpu->next;
196 freez(vcpu_f);
197 }
198
199 vbd = cur->vbd_root;
200 while(vbd) {
201 vbd_f = vbd;
202 vbd = vbd->next;
203 freez(vbd_f);
204 }
205
206 network = cur->network_root;
207 while(network) {
208 network_f = network;
209 network = network->next;
210 freez(network_f);
211 }
212
213 freez(cur);
214
215 return last ? last : NULL;
216 }
217
218 static int vcpu_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) {
219 unsigned int num_vcpus = 0;
220 xenstat_vcpu *vcpu = NULL;
221 struct vcpu_metrics *vcpu_m = NULL, *last_vcpu_m = NULL;
222
223 num_vcpus = xenstat_domain_num_vcpus(domain);
224
225 for(vcpu_m = d->vcpu_root; vcpu_m ; vcpu_m = vcpu_m->next)
226 vcpu_m->updated = 0;
227
228 vcpu_m = d->vcpu_root;
229
230 unsigned int i, num_online_vcpus=0;
231 for(i = 0; i < num_vcpus; i++) {
232 if(unlikely(!vcpu_m)) {
233 vcpu_m = callocz(1, sizeof(struct vcpu_metrics));
234
235 if(unlikely(i == 0)) d->vcpu_root = vcpu_m;
236 else last_vcpu_m->next = vcpu_m;
237 }
238
239 vcpu_m->id = i;
240
241 vcpu = xenstat_domain_vcpu(domain, i);
242
243 if(unlikely(!vcpu)) {
244 netdata_log_error("XENSTAT: cannot get VCPU statistics.");
245 return 1;
246 }
247
248 vcpu_m->online = xenstat_vcpu_online(vcpu);
249 if(likely(vcpu_m->online)) { num_online_vcpus++; }
250 vcpu_m->ns = xenstat_vcpu_ns(vcpu);
251
252 vcpu_m->updated = 1;
253
254 last_vcpu_m = vcpu_m;
255 vcpu_m = vcpu_m->next;
256 }
257
258 if(unlikely(num_online_vcpus != d->cur_vcpus)) {
259 d->num_vcpus_changed = 1;
260 d->cur_vcpus = num_online_vcpus;
261 }
262
263 return 0;
264 }
265
266 static int vbd_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) {
267 unsigned int num_vbds = xenstat_domain_num_vbds(domain);
268 xenstat_vbd *vbd = NULL;
269 struct vbd_metrics *vbd_m = NULL, *last_vbd_m = NULL;
270
271 for(vbd_m = d->vbd_root; vbd_m ; vbd_m = vbd_m->next)
272 vbd_m->updated = 0;
273
274 vbd_m = d->vbd_root;
275
276 unsigned int i;
277 for(i = 0; i < num_vbds; i++) {
278 if(unlikely(!vbd_m)) {
279 vbd_m = callocz(1, sizeof(struct vbd_metrics));
280
281 if(unlikely(i == 0)) d->vbd_root = vbd_m;
282 else last_vbd_m->next = vbd_m;
283 }
284
285 vbd_m->id = i;
286
287 vbd = xenstat_domain_vbd(domain, i);
288
289 if(unlikely(!vbd)) {
290 netdata_log_error("XENSTAT: cannot get VBD statistics.");
291 return 1;
292 }
293
294 #ifdef HAVE_XENSTAT_VBD_ERROR
295 vbd_m->error = xenstat_vbd_error(vbd);
296 #else
297 vbd_m->error = 0;
298 #endif
299 vbd_m->oo_reqs = xenstat_vbd_oo_reqs(vbd);
300 vbd_m->rd_reqs = xenstat_vbd_rd_reqs(vbd);
301 vbd_m->wr_reqs = xenstat_vbd_wr_reqs(vbd);
302 vbd_m->rd_sects = xenstat_vbd_rd_sects(vbd);
303 vbd_m->wr_sects = xenstat_vbd_wr_sects(vbd);
304
305 vbd_m->updated = 1;
306
307 last_vbd_m = vbd_m;
308 vbd_m = vbd_m->next;
309 }
310
311 return 0;
312 }
313
314 static int network_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) {
315 unsigned int num_networks = xenstat_domain_num_networks(domain);
316 xenstat_network *network = NULL;
317 struct network_metrics *network_m = NULL, *last_network_m = NULL;
318
319 for(network_m = d->network_root; network_m ; network_m = network_m->next)
320 network_m->updated = 0;
321
322 network_m = d->network_root;
323
324 unsigned int i;
325 for(i = 0; i < num_networks; i++) {
326 if(unlikely(!network_m)) {
327 network_m = callocz(1, sizeof(struct network_metrics));
328
329 if(unlikely(i == 0)) d->network_root = network_m;
330 else last_network_m->next = network_m;
331 }
332
333 network_m->id = i;
334
335 network = xenstat_domain_network(domain, i);
336
337 if(unlikely(!network)) {
338 netdata_log_error("XENSTAT: cannot get network statistics.");
339 return 1;
340 }
341
342 network_m->rbytes = xenstat_network_rbytes(network);
343 network_m->rpackets = xenstat_network_rpackets(network);
344 network_m->rerrs = xenstat_network_rerrs(network);
345 network_m->rdrops = xenstat_network_rdrop(network);
346
347 network_m->tbytes = xenstat_network_tbytes(network);
348 network_m->tpackets = xenstat_network_tpackets(network);
349 network_m->terrs = xenstat_network_terrs(network);
350 network_m->tdrops = xenstat_network_tdrop(network);
351
352 network_m->updated = 1;
353
354 last_network_m = network_m;
355 network_m = network_m->next;
356 }
357
358 return 0;
359 }
360
361 static int xenstat_collect(xenstat_handle *xhandle, libxl_ctx *ctx, libxl_dominfo *info) {
362
363 // mark all old metrics as not-updated
364 struct domain_metrics *d;
365 for(d = node_metrics.domain_root; d ; d = d->next)
366 d->updated = 0;
367
368 xenstat_node *node = xenstat_get_node(xhandle, XENSTAT_ALL);
369 if (unlikely(!node)) {
370 netdata_log_error("XENSTAT: failed to retrieve statistics from libxenstat.");
371 return 1;
372 }
373
374 node_metrics.tot_mem = xenstat_node_tot_mem(node);
375 node_metrics.free_mem = xenstat_node_free_mem(node);
376 node_metrics.num_domains = xenstat_node_num_domains(node);
377 node_metrics.num_cpus = xenstat_node_num_cpus(node);
378 node_metrics.node_cpu_hz = xenstat_node_cpu_hz(node);
379
380 int i;
381 for(i = 0; i < node_metrics.num_domains; i++) {
382 xenstat_domain *domain = NULL;
383 char uuid[LIBXL_UUID_FMTLEN + 1];
384
385 domain = xenstat_node_domain_by_index(node, i);
386
387 // get domain UUID
388 unsigned int id = xenstat_domain_id(domain);
389 if(unlikely(libxl_domain_info(ctx, info, id))) {
390 netdata_log_error("XENSTAT: cannot get domain info.");
391 continue;
392 }
393 else {
394 snprintfz(uuid, LIBXL_UUID_FMTLEN, LIBXL_UUID_FMT "\n", LIBXL_UUID_BYTES(info->uuid));
395 }
396
397 uint32_t hash = simple_hash(uuid);
398 d = domain_metrics_get(uuid, hash);
399
400 d->id = id;
401 if(unlikely(!d->name)) {
402 d->name = strdupz(xenstat_domain_name(domain));
403 netdata_fix_chart_id(d->name);
404 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: domain id %u, uuid %s has name '%s'\n", d->id, d->uuid, d->name);
405 }
406
407 d->running = xenstat_domain_running(domain);
408 d->blocked = xenstat_domain_blocked(domain);
409 d->paused = xenstat_domain_paused(domain);
410 d->shutdown = xenstat_domain_shutdown(domain);
411 d->crashed = xenstat_domain_crashed(domain);
412 d->dying = xenstat_domain_dying(domain);
413
414 d->cpu_ns = xenstat_domain_cpu_ns(domain);
415 d->cur_mem = xenstat_domain_cur_mem(domain);
416 d->max_mem = xenstat_domain_max_mem(domain);
417
418 if(unlikely(vcpu_metrics_collect(d, domain) || vbd_metrics_collect(d, domain) || network_metrics_collect(d, domain))) {
419 xenstat_free_node(node);
420 return 1;
421 }
422
423 d->updated = 1;
424 }
425
426 xenstat_free_node(node);
427
428 return 0;
429 }
430
431 static void xenstat_send_node_metrics() {
432 static int mem_chart_generated = 0, domains_chart_generated = 0, cpus_chart_generated = 0, cpu_freq_chart_generated = 0;
433
434 // ----------------------------------------------------------------
435
436 if(unlikely(!mem_chart_generated)) {
437 printf("CHART xenstat.mem '' 'Memory Usage' 'MiB' 'memory' '' stacked %d %d '' %s\n"
438 , NETDATA_CHART_PRIO_XENSTAT_NODE_MEM
439 , netdata_update_every
440 , PLUGIN_XENSTAT_NAME
441 );
442 printf("DIMENSION %s '' absolute 1 %d\n", "free", netdata_update_every * 1024 * 1024);
443 printf("DIMENSION %s '' absolute 1 %d\n", "used", netdata_update_every * 1024 * 1024);
444 mem_chart_generated = 1;
445 }
446
447 printf(
448 "BEGIN xenstat.mem\n"
449 "SET free = %lld\n"
450 "SET used = %lld\n"
451 "END\n"
452 , (collected_number) node_metrics.free_mem
453 , (collected_number) (node_metrics.tot_mem - node_metrics.free_mem)
454 );
455
456 // ----------------------------------------------------------------
457
458 if(unlikely(!domains_chart_generated)) {
459 printf("CHART xenstat.domains '' 'Number of Domains' 'domains' 'domains' '' line %d %d '' %s\n"
460 , NETDATA_CHART_PRIO_XENSTAT_NODE_DOMAINS
461 , netdata_update_every
462 , PLUGIN_XENSTAT_NAME
463 );
464 printf("DIMENSION %s '' absolute 1 %d\n", "domains", netdata_update_every);
465 domains_chart_generated = 1;
466 }
467
468 printf(
469 "BEGIN xenstat.domains\n"
470 "SET domains = %lld\n"
471 "END\n"
472 , (collected_number) node_metrics.num_domains
473 );
474
475 // ----------------------------------------------------------------
476
477 if(unlikely(!cpus_chart_generated)) {
478 printf("CHART xenstat.cpus '' 'Number of CPUs' 'cpus' 'cpu' '' line %d %d '' %s\n"
479 , NETDATA_CHART_PRIO_XENSTAT_NODE_CPUS
480 , netdata_update_every
481 , PLUGIN_XENSTAT_NAME
482 );
483 printf("DIMENSION %s '' absolute 1 %d\n", "cpus", netdata_update_every);
484 cpus_chart_generated = 1;
485 }
486
487 printf(
488 "BEGIN xenstat.cpus\n"
489 "SET cpus = %lld\n"
490 "END\n"
491 , (collected_number) node_metrics.num_cpus
492 );
493
494 // ----------------------------------------------------------------
495
496 if(unlikely(!cpu_freq_chart_generated)) {
497 printf("CHART xenstat.cpu_freq '' 'CPU Frequency' 'MHz' 'cpu' '' line %d %d '' %s\n"
498 , NETDATA_CHART_PRIO_XENSTAT_NODE_CPU_FREQ
499 , netdata_update_every
500 , PLUGIN_XENSTAT_NAME
501 );
502 printf("DIMENSION %s '' absolute 1 %d\n", "frequency", netdata_update_every * 1024 * 1024);
503 cpu_freq_chart_generated = 1;
504 }
505
506 printf(
507 "BEGIN xenstat.cpu_freq\n"
508 "SET frequency = %lld\n"
509 "END\n"
510 , (collected_number) node_metrics.node_cpu_hz
511 );
512 }
513
514 static void print_domain_states_chart_definition(char *type, int obsolete_flag) {
515 printf("CHART %s.states '' 'Domain States' 'boolean' 'states' 'xendomain.states' line %d %d %s %s\n"
516 , type
517 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_STATES
518 , netdata_update_every
519 , obsolete_flag ? "obsolete": "''"
520 , PLUGIN_XENSTAT_NAME
521 );
522 printf("DIMENSION running '' absolute 1 %d\n", netdata_update_every);
523 printf("DIMENSION blocked '' absolute 1 %d\n", netdata_update_every);
524 printf("DIMENSION paused '' absolute 1 %d\n", netdata_update_every);
525 printf("DIMENSION shutdown '' absolute 1 %d\n", netdata_update_every);
526 printf("DIMENSION crashed '' absolute 1 %d\n", netdata_update_every);
527 printf("DIMENSION dying '' absolute 1 %d\n", netdata_update_every);
528 }
529
530 static void print_domain_cpu_chart_definition(char *type, int obsolete_flag) {
531 printf("CHART %s.cpu '' 'CPU Usage (100%% = 1 core)' 'percentage' 'cpu' 'xendomain.cpu' line %d %d %s %s\n"
532 , type
533 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_CPU
534 , netdata_update_every
535 , obsolete_flag ? "obsolete": "''"
536 , PLUGIN_XENSTAT_NAME
537 );
538 printf("DIMENSION used '' incremental 100 %d\n", netdata_update_every * 1000000000);
539 }
540
541 static void print_domain_mem_chart_definition(char *type, int obsolete_flag) {
542 printf("CHART %s.mem '' 'Memory Reservation' 'MiB' 'memory' 'xendomain.mem' line %d %d %s %s\n"
543 , type
544 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_MEM
545 , netdata_update_every
546 , obsolete_flag ? "obsolete": "''"
547 , PLUGIN_XENSTAT_NAME
548 );
549 printf("DIMENSION maximum '' absolute 1 %d\n", netdata_update_every * 1024 * 1024);
550 printf("DIMENSION current '' absolute 1 %d\n", netdata_update_every * 1024 * 1024);
551 }
552
553 static void print_domain_vcpu_chart_definition(char *type, struct domain_metrics *d, int obsolete_flag) {
554 struct vcpu_metrics *vcpu_m;
555
556 printf("CHART %s.vcpu '' 'CPU Usage per VCPU' 'percentage' 'cpu' 'xendomain.vcpu' line %d %d %s %s\n"
557 , type
558 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VCPU
559 , netdata_update_every
560 , obsolete_flag ? "obsolete": "''"
561 , PLUGIN_XENSTAT_NAME
562 );
563
564 for(vcpu_m = d->vcpu_root; vcpu_m; vcpu_m = vcpu_m->next) {
565 if(likely(vcpu_m->updated && vcpu_m->online)) {
566 printf("DIMENSION vcpu%u '' incremental 100 %d\n", vcpu_m->id, netdata_update_every * 1000000000);
567 }
568 }
569 }
570
571 static void print_domain_vbd_oo_chart_definition(char *type, unsigned int vbd, int obsolete_flag) {
572 printf("CHART %s.oo_req_vbd%u '' 'VBD%u \"Out Of\" Requests' 'requests/s' 'vbd' 'xendomain.oo_req_vbd' line %u %d %s %s\n"
573 , type
574 , vbd
575 , vbd
576 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_OO_REQ + vbd
577 , netdata_update_every
578 , obsolete_flag ? "obsolete": "''"
579 , PLUGIN_XENSTAT_NAME
580 );
581 printf("DIMENSION requests '' incremental 1 %d\n", netdata_update_every);
582 }
583
584 static void print_domain_vbd_requests_chart_definition(char *type, unsigned int vbd, int obsolete_flag) {
585 printf("CHART %s.requests_vbd%u '' 'VBD%u Requests' 'requests/s' 'vbd' 'xendomain.requests_vbd' line %u %d %s %s\n"
586 , type
587 , vbd
588 , vbd
589 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_REQUESTS + vbd
590 , netdata_update_every
591 , obsolete_flag ? "obsolete": "''"
592 , PLUGIN_XENSTAT_NAME
593 );
594 printf("DIMENSION read '' incremental 1 %d\n", netdata_update_every);
595 printf("DIMENSION write '' incremental -1 %d\n", netdata_update_every);
596 }
597
598 static void print_domain_vbd_sectors_chart_definition(char *type, unsigned int vbd, int obsolete_flag) {
599 printf("CHART %s.sectors_vbd%u '' 'VBD%u Read/Written Sectors' 'sectors/s' 'vbd' 'xendomain.sectors_vbd' line %u %d %s %s\n"
600 , type
601 , vbd
602 , vbd
603 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_SECTORS + vbd
604 , netdata_update_every
605 , obsolete_flag ? "obsolete": "''"
606 , PLUGIN_XENSTAT_NAME
607 );
608 printf("DIMENSION read '' incremental 1 %d\n", netdata_update_every);
609 printf("DIMENSION write '' incremental -1 %d\n", netdata_update_every);
610 }
611
612 static void print_domain_network_bytes_chart_definition(char *type, unsigned int network, int obsolete_flag) {
613 printf("CHART %s.bytes_network%u '' 'Network%u Received/Sent Bytes' 'kilobits/s' 'network' 'xendomain.bytes_network' line %u %d %s %s\n"
614 , type
615 , network
616 , network
617 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_BYTES + network
618 , netdata_update_every
619 , obsolete_flag ? "obsolete": "''"
620 , PLUGIN_XENSTAT_NAME
621 );
622 printf("DIMENSION received '' incremental 8 %d\n", netdata_update_every * 1000);
623 printf("DIMENSION sent '' incremental -8 %d\n", netdata_update_every * 1000);
624 }
625
626 static void print_domain_network_packets_chart_definition(char *type, unsigned int network, int obsolete_flag) {
627 printf("CHART %s.packets_network%u '' 'Network%u Received/Sent Packets' 'packets/s' 'network' 'xendomain.packets_network' line %u %d %s %s\n"
628 , type
629 , network
630 , network
631 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network
632 , netdata_update_every
633 , obsolete_flag ? "obsolete": "''"
634 , PLUGIN_XENSTAT_NAME
635 );
636 printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every);
637 printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every);
638 }
639
640 static void print_domain_network_errors_chart_definition(char *type, unsigned int network, int obsolete_flag) {
641 printf("CHART %s.errors_network%u '' 'Network%u Receive/Transmit Errors' 'errors/s' 'network' 'xendomain.errors_network' line %u %d %s %s\n"
642 , type
643 , network
644 , network
645 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network
646 , netdata_update_every
647 , obsolete_flag ? "obsolete": "''"
648 , PLUGIN_XENSTAT_NAME
649 );
650 printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every);
651 printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every);
652 }
653
654 static void print_domain_network_drops_chart_definition(char *type, unsigned int network, int obsolete_flag) {
655 printf("CHART %s.drops_network%u '' 'Network%u Receive/Transmit Drops' 'drops/s' 'network' 'xendomain.drops_network' line %u %d %s %s\n"
656 , type
657 , network
658 , network
659 , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network
660 , netdata_update_every
661 , obsolete_flag ? "obsolete": "''"
662 , PLUGIN_XENSTAT_NAME
663 );
664 printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every);
665 printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every);
666 }
667
668 static void xenstat_send_domain_metrics() {
669
670 if(unlikely(!node_metrics.domain_root)) return;
671 struct domain_metrics *d;
672
673 for(d = node_metrics.domain_root; d; d = d->next) {
674 char type[TYPE_LENGTH_MAX + 1];
675 snprintfz(type, TYPE_LENGTH_MAX, "xendomain_%s_%s", d->name, d->uuid);
676
677 if(likely(d->updated)) {
678
679 // ----------------------------------------------------------------
680
681 if(unlikely(!d->states_chart_generated)) {
682 print_domain_states_chart_definition(type, CHART_IS_NOT_OBSOLETE);
683 d->states_chart_generated = 1;
684 }
685 printf(
686 "BEGIN %s.states\n"
687 "SET running = %lld\n"
688 "SET blocked = %lld\n"
689 "SET paused = %lld\n"
690 "SET shutdown = %lld\n"
691 "SET crashed = %lld\n"
692 "SET dying = %lld\n"
693 "END\n"
694 , type
695 , (collected_number)d->running
696 , (collected_number)d->blocked
697 , (collected_number)d->paused
698 , (collected_number)d->shutdown
699 , (collected_number)d->crashed
700 , (collected_number)d->dying
701 );
702
703 // ----------------------------------------------------------------
704
705 if(unlikely(!d->cpu_chart_generated)) {
706 print_domain_cpu_chart_definition(type, CHART_IS_NOT_OBSOLETE);
707 d->cpu_chart_generated = 1;
708 }
709 printf(
710 "BEGIN %s.cpu\n"
711 "SET used = %lld\n"
712 "END\n"
713 , type
714 , (collected_number)d->cpu_ns
715 );
716
717 // ----------------------------------------------------------------
718
719 struct vcpu_metrics *vcpu_m;
720
721 if(unlikely(!d->vcpu_chart_generated || d->num_vcpus_changed)) {
722 print_domain_vcpu_chart_definition(type, d, CHART_IS_NOT_OBSOLETE);
723 d->num_vcpus_changed = 0;
724 d->vcpu_chart_generated = 1;
725 }
726
727 printf("BEGIN %s.vcpu\n", type);
728 for(vcpu_m = d->vcpu_root; vcpu_m; vcpu_m = vcpu_m->next) {
729 if(likely(vcpu_m->updated && vcpu_m->online)) {
730 printf(
731 "SET vcpu%u = %lld\n"
732 , vcpu_m->id
733 , (collected_number)vcpu_m->ns
734 );
735 }
736 }
737 printf("END\n");
738
739 // ----------------------------------------------------------------
740
741 if(unlikely(!d->mem_chart_generated)) {
742 print_domain_mem_chart_definition(type, CHART_IS_NOT_OBSOLETE);
743 d->mem_chart_generated = 1;
744 }
745 printf(
746 "BEGIN %s.mem\n"
747 "SET maximum = %lld\n"
748 "SET current = %lld\n"
749 "END\n"
750 , type
751 , (collected_number)d->max_mem
752 , (collected_number)d->cur_mem
753 );
754
755 // ----------------------------------------------------------------
756
757 struct vbd_metrics *vbd_m;
758 for(vbd_m = d->vbd_root; vbd_m; vbd_m = vbd_m->next) {
759 if(likely(vbd_m->updated && !vbd_m->error)) {
760 if(unlikely(!vbd_m->oo_req_chart_generated)) {
761 print_domain_vbd_oo_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE);
762 vbd_m->oo_req_chart_generated = 1;
763 }
764 printf(
765 "BEGIN %s.oo_req_vbd%u\n"
766 "SET requests = %lld\n"
767 "END\n"
768 , type
769 , vbd_m->id
770 , (collected_number)vbd_m->oo_reqs
771 );
772
773 // ----------------------------------------------------------------
774
775 if(unlikely(!vbd_m->requests_chart_generated)) {
776 print_domain_vbd_requests_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE);
777 vbd_m->requests_chart_generated = 1;
778 }
779 printf(
780 "BEGIN %s.requests_vbd%u\n"
781 "SET read = %lld\n"
782 "SET write = %lld\n"
783 "END\n"
784 , type
785 , vbd_m->id
786 , (collected_number)vbd_m->rd_reqs
787 , (collected_number)vbd_m->wr_reqs
788 );
789
790 // ----------------------------------------------------------------
791
792 if(unlikely(!vbd_m->sectors_chart_generated)) {
793 print_domain_vbd_sectors_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE);
794 vbd_m->sectors_chart_generated = 1;
795 }
796 printf(
797 "BEGIN %s.sectors_vbd%u\n"
798 "SET read = %lld\n"
799 "SET write = %lld\n"
800 "END\n"
801 , type
802 , vbd_m->id
803 , (collected_number)vbd_m->rd_sects
804 , (collected_number)vbd_m->wr_sects
805 );
806 }
807 else {
808 if(unlikely(vbd_m->oo_req_chart_generated
809 || vbd_m->requests_chart_generated
810 || vbd_m->sectors_chart_generated)) {
811 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: mark charts as obsolete for vbd %u, domain '%s', id %u, uuid %s\n", vbd_m->id, d->name, d->id, d->uuid);
812 print_domain_vbd_oo_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE);
813 print_domain_vbd_requests_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE);
814 print_domain_vbd_sectors_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE);
815 vbd_m->oo_req_chart_generated = 0;
816 vbd_m->requests_chart_generated = 0;
817 vbd_m->sectors_chart_generated = 0;
818 }
819 }
820 }
821
822 // ----------------------------------------------------------------
823
824 struct network_metrics *network_m;
825 for(network_m = d->network_root; network_m; network_m = network_m->next) {
826 if(likely(network_m->updated)) {
827 if(unlikely(!network_m->bytes_chart_generated)) {
828 print_domain_network_bytes_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
829 network_m->bytes_chart_generated = 1;
830 }
831 printf(
832 "BEGIN %s.bytes_network%u\n"
833 "SET received = %lld\n"
834 "SET sent = %lld\n"
835 "END\n"
836 , type
837 , network_m->id
838 , (collected_number)network_m->rbytes
839 , (collected_number)network_m->tbytes
840 );
841
842 // ----------------------------------------------------------------
843
844 if(unlikely(!network_m->packets_chart_generated)) {
845 print_domain_network_packets_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
846 network_m->packets_chart_generated = 1;
847 }
848 printf(
849 "BEGIN %s.packets_network%u\n"
850 "SET received = %lld\n"
851 "SET sent = %lld\n"
852 "END\n"
853 , type
854 , network_m->id
855 , (collected_number)network_m->rpackets
856 , (collected_number)network_m->tpackets
857 );
858
859 // ----------------------------------------------------------------
860
861 if(unlikely(!network_m->errors_chart_generated)) {
862 print_domain_network_errors_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
863 network_m->errors_chart_generated = 1;
864 }
865 printf(
866 "BEGIN %s.errors_network%u\n"
867 "SET received = %lld\n"
868 "SET sent = %lld\n"
869 "END\n"
870 , type
871 , network_m->id
872 , (collected_number)network_m->rerrs
873 , (collected_number)network_m->terrs
874 );
875
876 // ----------------------------------------------------------------
877
878 if(unlikely(!network_m->drops_chart_generated)) {
879 print_domain_network_drops_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
880 network_m->drops_chart_generated = 1;
881 }
882 printf(
883 "BEGIN %s.drops_network%u\n"
884 "SET received = %lld\n"
885 "SET sent = %lld\n"
886 "END\n"
887 , type
888 , network_m->id
889 , (collected_number)network_m->rdrops
890 , (collected_number)network_m->tdrops
891 );
892 }
893 else {
894 if(unlikely(network_m->bytes_chart_generated
895 || network_m->packets_chart_generated
896 || network_m->errors_chart_generated
897 || network_m->drops_chart_generated))
898 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: mark charts as obsolete for network %u, domain '%s', id %u, uuid %s\n", network_m->id, d->name, d->id, d->uuid);
899 print_domain_network_bytes_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
900 print_domain_network_packets_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
901 print_domain_network_errors_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
902 print_domain_network_drops_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
903 network_m->bytes_chart_generated = 0;
904 network_m->packets_chart_generated = 0;
905 network_m->errors_chart_generated = 0;
906 network_m->drops_chart_generated = 0;
907 }
908 }
909 }
910 else{
911 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: mark charts as obsolete for domain '%s', id %u, uuid %s\n", d->name, d->id, d->uuid);
912 print_domain_states_chart_definition(type, CHART_IS_OBSOLETE);
913 print_domain_cpu_chart_definition(type, CHART_IS_OBSOLETE);
914 print_domain_vcpu_chart_definition(type, d, CHART_IS_OBSOLETE);
915 print_domain_mem_chart_definition(type, CHART_IS_OBSOLETE);
916
917 d = domain_metrics_free(d);
918 }
919 }
920 }
921
922 int main(int argc, char **argv) {
923 // ------------------------------------------------------------------------
924 // initialization of netdata plugin
925
926 program_name = PLUGIN_XENSTAT_NAME;
927
928 nd_log_initialize_for_external_plugins(PLUGIN_XENSTAT_NAME);
929 netdata_threads_init_for_external_plugins(0);
930
931 // ------------------------------------------------------------------------
932 // parse command line parameters
933
934 int i, freq = 0;
935 for(i = 1; i < argc ; i++) {
936 if(isdigit(*argv[i]) && !freq) {
937 int n = str2i(argv[i]);
938 if(n > 0 && n < 86400) {
939 freq = n;
940 continue;
941 }
942 }
943 else if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
944 printf("xenstat.plugin %s\n", NETDATA_VERSION);
945 exit(0);
946 }
947 else if(strcmp("debug", argv[i]) == 0) {
948 debug = 1;
949 continue;
950 }
951 else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
952 fprintf(stderr,
953 "\n"
954 " netdata xenstat.plugin %s\n"
955 " Copyright 2018-2025 Netdata Inc.\n"
956 " Released under GNU General Public License v3 or later.\n"
957 "\n"
958 " This program is a data collector plugin for netdata.\n"
959 "\n"
960 " Available command line options:\n"
961 "\n"
962 " COLLECTION_FREQUENCY data collection frequency in seconds\n"
963 " minimum: %d\n"
964 "\n"
965 " debug enable verbose output\n"
966 " default: disabled\n"
967 "\n"
968 " -v\n"
969 " -V\n"
970 " --version print version and exit\n"
971 "\n"
972 " -h\n"
973 " --help print this message and exit\n"
974 "\n"
975 " For more information:\n"
976 " https://github.com/netdata/netdata/tree/master/src/collectors/xenstat.plugin\n"
977 "\n"
978 , NETDATA_VERSION
979 , netdata_update_every
980 );
981 exit(1);
982 }
983
984 netdata_log_error("xenstat.plugin: ignoring parameter '%s'", argv[i]);
985 }
986
987 errno_clear();
988
989 if(freq >= netdata_update_every)
990 netdata_update_every = freq;
991 else if(freq)
992 netdata_log_error("update frequency %d seconds is too small for XENSTAT. Using %d.", freq, netdata_update_every);
993
994 // ------------------------------------------------------------------------
995 // initialize xen API handles
996 xenstat_handle *xhandle = NULL;
997 libxl_ctx *ctx = NULL;
998 libxl_dominfo info;
999
1000 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_init()\n");
1001 xhandle = xenstat_init();
1002 if (xhandle == NULL) {
1003 netdata_log_error("XENSTAT: failed to initialize xenstat library.");
1004 return 1;
1005 }
1006
1007 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling libxl_ctx_alloc()\n");
1008 if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, NULL)) {
1009 netdata_log_error("XENSTAT: failed to initialize xl context.");
1010 xenstat_uninit(xhandle);
1011 return 1;
1012 }
1013 libxl_dominfo_init(&info);
1014
1015 // ------------------------------------------------------------------------
1016 // the main loop
1017
1018 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: starting data collection\n");
1019
1020 time_t started_t = now_monotonic_sec();
1021
1022 size_t iteration;
1023
1024 heartbeat_t hb;
1025 heartbeat_init(&hb, netdata_update_every * USEC_PER_SEC);
1026 for(iteration = 0; 1; iteration++) {
1027 usec_t dt = heartbeat_next(&hb);
1028
1029 if(unlikely(exit_initiated_get())) break;
1030
1031 if(unlikely(debug && iteration))
1032 fprintf(stderr, "xenstat.plugin: iteration %zu, dt %lu usec\n", iteration, dt);
1033
1034 if(likely(xhandle)) {
1035 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_collect()\n");
1036 int ret = xenstat_collect(xhandle, ctx, &info);
1037
1038 if(likely(!ret)) {
1039 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_send_node_metrics()\n");
1040 xenstat_send_node_metrics();
1041 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_send_domain_metrics()\n");
1042 xenstat_send_domain_metrics();
1043 }
1044 else {
1045 if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: can't collect data\n");
1046 }
1047 }
1048
1049 fflush(stdout);
1050
1051 // restart check (14400 seconds)
1052 if(unlikely(now_monotonic_sec() - started_t > 14400)) break;
1053 }
1054
1055 libxl_ctx_free(ctx);
1056 xenstat_uninit(xhandle);
1057 netdata_log_info("XENSTAT process exiting");
1058
1059 return 0;
1060 }