2
* Copyright (C) 2002-04 Luca Deri <deri@ntop.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
/* This plugin works only with threads */
23
/* #define RRD_DEBUG 8 */
33
2.0 Rolled major version due to new interface parameter.
34
2.1 Added tests/creates for rrd and subdirectories, fixed timer,
35
--reuse-rrd-graphics etc.
36
2.1.1 Fixed hosts / interface bug (Luca)
37
2.1.2 Added status message
38
2.2 Version roll (preparatory) for ntop 2.2
40
2.2b Large rrd population option
41
2.3 Updates, fixes, etc ... for ntop 2.3
43
Remember, there are TWO paths into this - one is through the main loop,
44
if the plugin is active, the other is through the http function if the
45
plugin is NOT active. So initialize stuff in BOTH places!
48
Aberrant RRD Behavior (http://cricket.sourceforge.net/aberrant/)
49
patch courtesy of Dominique Karg <dk@ipsoluciones.com>
54
static const char *rrd_subdirs[] =
55
{ "graphics", /* graphics sub directory - must be first */
61
#include "globals-report.h"
65
static void setPluginStatus(char * status);
66
#ifdef CFG_MULTITHREADED
67
static PthreadMutex rrdMutex;
74
static unsigned short initialized = 0, active = 0, dumpInterval, dumpDetail;
75
static unsigned short dumpDays, dumpHours, dumpMonths;
76
static char *hostsFilter = NULL;
77
static Counter numTotalRRDs = 0;
78
static unsigned long numRuns = 0, numRRDerrors = 0;
79
static time_t start_tm, end_tm, rrdTime;
81
#ifdef CFG_MULTITHREADED
85
static u_short dumpDomains, dumpFlows, dumpHosts, dumpInterfaces, dumpMatrix, shownCreate=0;
87
static u_short dumpPermissions;
90
static Counter rrdGraphicRequests=0;
93
static struct dirent *workDirent;
96
char startTimeBuf[32], endTimeBuf[32], fileTimeBuf[32];
100
int sumCounter(char *rrdPath, char *rrdFilePath,
101
char *startTime, char* endTime, Counter *total, float *average);
102
void graphCounter(char *rrdPath, char *rrdName, char *rrdTitle,
103
char *startTime, char* endTime, char* rrdPrefix);
104
void updateCounter(char *hostPath, char *key, Counter value);
105
void updateGauge(char *hostPath, char *key, Counter value);
106
void updateTrafficCounter(char *hostPath, char *key, TrafficCounter *counter);
107
char x2c(char *what);
108
void unescape_url(char *url);
109
void mkdir_p(char *path);
110
static int initRRDfunct(void);
111
static void termRRDfunct(void);
112
static void handleRRDHTTPrequest(char* url);
114
/* ************************************* */
116
static PluginInfo rrdPluginInfo[] = {
118
VERSION, /* current ntop version */
120
"This plugin is used to setup, activate and deactivate ntop's rrd support.<br>"
121
"This plugin also produces the graphs of rrd data, available via a "
122
"link from the various 'Info about host xxxxx' reports.",
124
"<a HREF=\"http://luca.ntop.org/\" alt=\"Luca's home page\">L.Deri</A>",
125
"rrdPlugin", /* http://<host>:<port>/plugins/rrdPlugin */
126
1, /* Active by default */
127
1, /* Inactive setup */
128
initRRDfunct, /* TermFunc */
129
termRRDfunct, /* TermFunc */
130
NULL, /* PluginFunc */
131
handleRRDHTTPrequest,
132
NULL, /* no capture */
137
/* ****************************************************** */
139
static char **calcpr=NULL;
141
static void calfree (void) {
144
for(i=0;calcpr[i];i++){
155
/* ******************************************* */
158
void revertSlash(char *str, int mode) {
161
for(i=0; str[i] != '\0'; i++)
164
if(str[i] == '/') str[i] = '\\';
167
if(str[i] == '\\') str[i] = '/';
172
void revertDoubleColumn(char *str) {
176
for(i=0, j=0; str[i] != '\0'; i++) {
191
/* ******************************************* */
194
#define _mkdir(a) mkdir(a)
196
#define _mkdir(a) mkdir(a, myGlobals.rrdDirectoryPermissions)
199
void mkdir_p(char *path) {
203
traceEvent(CONST_TRACE_NOISY, "RRD: mkdir(null) skipped");
208
revertSlash(path, 0);
211
/* Start at 1 to skip the root */
212
for(i=1; path[i] != '\0'; i++)
213
if(path[i] == CONST_PATH_SEP) {
216
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: calling mkdir(%s)", path);
219
if((rc != 0) && (errno != EEXIST) )
220
traceEvent(CONST_TRACE_WARNING, "RRD: %s, error %d %s",
224
path[i] = CONST_PATH_SEP;
228
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: calling mkdir(%s)", path);
231
if((rc != 0) && (errno != EEXIST) )
232
traceEvent(CONST_TRACE_WARNING, "RRD: %s, error %d %s",
238
/* ******************************************* */
240
static void fillupArgv(int argc, int maxArgc, char *argv[]) {
243
for(i=argc; i<maxArgc; i++)
249
/* ******************************************* */
251
int sumCounter(char *rrdPath, char *rrdFilePath,
252
char *startTime, char* endTime, Counter *total, float *average) {
253
char *argv[32], path[512];
256
unsigned long step, ds_cnt,i;
257
rrd_value_t *data,*datai, _total, _val;
260
if(snprintf(path, sizeof(path), "%s/%s/%s",
261
myGlobals.rrdPath, rrdPath, rrdFilePath) < 0)
265
revertSlash(path, 0);
268
argv[argc++] = "rrd_fetch";
270
argv[argc++] = "AVERAGE";
271
argv[argc++] = "--start";
272
argv[argc++] = startTime;
273
argv[argc++] = "--end";
274
argv[argc++] = endTime;
276
#ifdef CFG_MULTITHREADED
277
accessMutex(&rrdMutex, "rrd_fetch");
279
optind=0; /* reset gnu getopt */
280
opterr=0; /* no error messages */
282
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
285
rc = rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &ds_namv, &data);
287
#ifdef CFG_MULTITHREADED
288
releaseMutex(&rrdMutex);
295
for (x = 0; x < argc; x++)
296
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: argv[%d] = %s", x, argv[x]);
302
datai = data, _total = 0;
304
for(i = start; i <= end; i += step) {
311
for(i=0;i<ds_cnt;i++) free(ds_namv[i]);
315
(*total) = _total*step;
316
(*average) = (float)(*total)/(float)(end-start);
321
/* ******************************************* */
323
static void listResource(char *rrdPath, char *rrdTitle,
324
char *startTime, char* endTime) {
325
char path[512], url[256], formatBuf[32];
326
DIR* directoryPointer=NULL;
330
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
332
if(snprintf(path, sizeof(path), "%s/%s", myGlobals.rrdPath, rrdPath) < 0)
336
revertSlash(path, 0);
339
directoryPointer = opendir(path);
341
if(directoryPointer == NULL) {
343
if(snprintf(buf, sizeof(buf), "<I>Unable to read directory %s</I>", path) < 0)
345
printFlagedWarning(buf);
350
if(snprintf(path, sizeof(path), "Info about %s", rrdTitle) < 0)
353
printHTMLheader(path, NULL, 0);
354
sendString("<CENTER>\n<p ALIGN=right>\n");
356
if(snprintf(url, sizeof(url),
357
"/plugins/rrdPlugin?action=list&key=%s&title=%s&end=now",
358
rrdPath, rrdTitle) < 0)
361
if(snprintf(path, sizeof(path), "<b>View:</b> [ <A HREF=\"%s&start=now-1y\">year</A> ]", url) < 0)
364
if(snprintf(path, sizeof(path), "[ <A HREF=\"%s&start=now-1m\">month</A> ]", url) < 0)
367
if(snprintf(path, sizeof(path), "[ <A HREF=\"%s&start=now-1w\">week</A> ]", url) < 0)
370
if(snprintf(path, sizeof(path), "[ <A HREF=\"%s&start=now-1d\">day</A> ]", url) < 0)
373
if(snprintf(path, sizeof(path), "[ <A HREF=\"%s&start=now-12h\">last 12h</A> ]\n", url) < 0)
376
if(snprintf(path, sizeof(path), "[ <A HREF=\"%s&start=now-6h\">last 6h</A> ]\n", url) < 0)
379
if(snprintf(path, sizeof(path), "[ <A HREF=\"%s&start=now-1h\">last hour</A> ] \n", url) < 0)
383
sendString("</p>\n<p>\n<TABLE BORDER=1 "TABLE_DEFAULTS">\n");
385
sendString("<TR><TH "DARK_BG">Graph</TH><TH "DARK_BG">Total</TH></TR>\n");
387
while((dp = readdir(directoryPointer)) != NULL) {
393
if(dp->d_name[0] == '.')
395
else if(strlen(dp->d_name) < strlen(CONST_RRD_EXTENSION)+3)
398
rsrcName = &dp->d_name[strlen(dp->d_name)-strlen(CONST_RRD_EXTENSION)-3];
399
if(strcmp(rsrcName, "Num"CONST_RRD_EXTENSION) == 0)
404
rsrcName = &dp->d_name[strlen(dp->d_name)-strlen(CONST_RRD_EXTENSION)];
405
if(strcmp(rsrcName, CONST_RRD_EXTENSION))
408
rc = sumCounter(rrdPath, dp->d_name, startTime, endTime, &total, &average);
411
|| ((rc >= 0) && (total > 0))) {
413
rsrcName = dp->d_name;
415
sendString("<TR><TD>\n");
417
if(snprintf(path, sizeof(path), "<IMG SRC=\"/plugins/rrdPlugin?action=graph&key=%s/&name=%s&title=%s&start=%s&end=%s\"><P>\n",
418
rrdPath, rsrcName, rsrcName, startTime, endTime) < 0)
422
sendString("</TD><TD ALIGN=RIGHT>\n");
424
/* printf("rsrcName: %s\n", rsrcName); */
427
sendString(" ");
429
if((strncmp(rsrcName, "pkt", 3) == 0)
430
|| ((strlen(rsrcName) > 4) && (strcmp(&rsrcName[strlen(rsrcName)-4], "Pkts") == 0))) {
431
if(snprintf(path, sizeof(path), "%s Pkt</TD>",
432
formatPkts(total, formatBuf, sizeof(formatBuf))) < 0)
435
if(snprintf(path, sizeof(path), "%s",
436
formatBytes(total, 1, formatBuf, sizeof(formatBuf))) < 0)
442
sendString("</TD></TR>\n");
447
closedir(directoryPointer);
449
/* if(numEntries > 0) */ {
450
sendString("</TABLE>\n");
453
sendString("</CENTER>");
454
sendString("<br><b>NOTE: total and average values are NOT absolute but calculated on the specified time interval.</b>\n");
459
/* ******************************************* */
461
static int endsWith(char* label, char* pattern) {
462
int lenLabel, lenPattern;
464
lenLabel = strlen(label);
465
lenPattern = strlen(pattern);
467
if(lenPattern >= lenLabel)
470
return(!strcmp(&label[lenLabel-lenPattern], pattern));
473
/* ******************************************* */
475
void graphCounter(char *rrdPath, char *rrdName, char *rrdTitle,
476
char *startTime, char* endTime, char *rrdPrefix) {
477
char path[512], *argv[32], buf[384], buf1[384], fname[384], *label;
478
#ifdef HAVE_RRD_ABERRANT_BEHAVIOR
479
char buf2[384], buf3[384], buf4[384];
482
int argc = 0, rc, x, y;
484
if(snprintf(path, sizeof(path), "%s/%s%s.rrd", myGlobals.rrdPath, rrdPath, rrdName) < 0)
487
/* startTime[4] skips the 'now-' */
488
if(snprintf(fname, sizeof(fname), "%s/%s/%s-%s%s%s",
489
myGlobals.rrdPath, rrd_subdirs[0], startTime, rrdPrefix, rrdName,
494
revertSlash(path, 0);
495
revertSlash(fname, 0);
498
if(endsWith(rrdName, "Bytes")) label = "Bytes/sec";
499
else if(endsWith(rrdName, "Pkts")) label = "Packets/sec";
500
else label = rrdName;
502
rrdGraphicRequests++;
504
if(stat(path, &statbuf) == 0) {
505
argv[argc++] = "rrd_graph";
506
argv[argc++] = fname;
507
argv[argc++] = "--lazy";
508
argv[argc++] = "--imgformat";
509
argv[argc++] = "PNG";
510
argv[argc++] = "--vertical-label";
511
argv[argc++] = label;
512
argv[argc++] = "--start";
513
argv[argc++] = startTime;
514
argv[argc++] = "--end";
515
argv[argc++] = endTime;
516
#ifdef CONST_RRD_DEFAULT_FONT_NAME
517
argv[argc++] = "--font";
518
#ifdef CONST_RRD_DEFAULT_FONT_PATH
519
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \
520
CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME;
522
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME;
526
revertDoubleColumn(path);
528
if(snprintf(buf, sizeof(buf), "DEF:ctr=%s:counter:AVERAGE", path) < 0)
531
if(snprintf(buf1, sizeof(buf1), "AREA:ctr#00a000:%s", rrdTitle) < 0)
534
argv[argc++] = "GPRINT:ctr:MIN:Min\\: %3.1lf%s";
535
argv[argc++] = "GPRINT:ctr:MAX:Max\\: %3.1lf%s";
536
argv[argc++] = "GPRINT:ctr:AVERAGE:Avg\\: %3.1lf%s";
537
argv[argc++] = "GPRINT:ctr:LAST:Current\\: %3.1lf%s";
538
#ifdef HAVE_RRD_ABERRANT_BEHAVIOR
539
if(snprintf(buf2, sizeof(buf2), "DEF:pred=%s:counter:HWPREDICT", path) < 0)
542
if(snprintf(buf3, sizeof(buf3), "DEF:dev=%s:counter:DEVPREDICT", path) < 0)
545
if(snprintf(buf4, sizeof(buf4), "DEF:fail=%s:counter:FAILURES", path) < 0)
548
argv[argc++] = "TICK:fail#ffffa0:1.0:Anomalia";
549
argv[argc++] = "CDEF:upper=pred,dev,2,*,+";
550
argv[argc++] = "CDEF:lower=pred,dev,2,*,-";
551
argv[argc++] = "LINE1:upper#ff0000:Upper";
552
argv[argc++] = "LINE2:lower#ff0000:Lower";
555
#ifdef CFG_MULTITHREADED
556
accessMutex(&rrdMutex, "rrd_graph");
558
optind=0; /* reset gnu getopt */
559
opterr=0; /* no error messages */
561
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
563
rc = rrd_graph(argc, argv, &calcpr, &x, &y);
568
sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1);
569
sendGraphFile(fname, 0);
573
for (x = 0; x < argc; x++)
574
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: argv[%d] = %s", x, argv[x]);
577
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
578
printHTMLheader("RRD Graph", NULL, 0);
579
if(snprintf(path, sizeof(path),
580
"<I>Error while building graph of the requested file. %s</I>",
581
rrd_get_error()) < 0)
583
printFlagedWarning(path);
587
#ifdef CFG_MULTITHREADED
588
releaseMutex(&rrdMutex);
591
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
592
printHTMLheader("RRD Graph", NULL, 0);
593
printFlagedWarning("<I>Error while building graph of the requested file "
594
"(unknown RRD file)</I>");
598
/* ******************************* */
600
static void updateRRD(char *hostPath, char *key, Counter value, int isCounter) {
601
char path[512], *argv[32], cmd[64];
603
int argc = 0, rc, createdCounter = 0, i;
605
if(value == 0) return;
607
if(snprintf(path, sizeof(path), "%s%s.rrd", hostPath, key) < 0)
610
/* Avoid path problems */
611
for(i=strlen(hostPath); i<strlen(path); i++)
612
if(path[i] == '/') path[i]='_';
615
revertSlash(path, 0);
618
if(stat(path, &statbuf) != 0) {
619
char startStr[32], stepStr[32], counterStr[64], intervalStr[32];
620
char minStr[32], maxStr[32], daysStr[32], monthsStr[32];
621
#ifdef HAVE_RRD_ABERRANT_BEHAVIOR
624
int step = dumpInterval;
626
unsigned long topValue;
628
topValue = 1000000000 /* 1 Gbit/s */;
630
if(strncmp(key, "pkt", 3) == 0) {
631
topValue /= 8*64 /* 64 bytes is the shortest packet we care of */;
633
topValue /= 8 /* 8 bytes */;
636
argv[argc++] = "rrd_create";
638
argv[argc++] = "--start";
639
if(snprintf(startStr, sizeof(startStr), "%u",
640
rrdTime-1 /* -1 avoids subsequent rrd_update call problems */) < 0)
642
argv[argc++] = startStr;
644
argv[argc++] = "--step";
645
if(snprintf(stepStr, sizeof(stepStr), "%u", dumpInterval) < 0)
647
argv[argc++] = stepStr;
650
if(snprintf(counterStr, sizeof(counterStr), "DS:counter:COUNTER:%d:0:%u", step, topValue) < 0)
654
if(snprintf(counterStr, sizeof(counterStr), "DS:counter:GAUGE:%d:0:U", step) < 0)
657
argv[argc++] = counterStr;
659
/* dumpInterval is in seconds. There are 60m*60s = 3600s in an hour.
660
* value1 is the # of dumpIntervals per hour
662
value1 = (60*60 + dumpInterval - 1) / dumpInterval;
663
/* value2 is the # of value1 (hours) for dumpHours hours */
664
value2 = value1 * dumpHours;
665
if(snprintf(intervalStr, sizeof(intervalStr), "RRA:AVERAGE:%.1f:1:%d", 0.5, value2) < 0)
667
argv[argc++] = intervalStr;
669
/* Store the MIN/MAX 5m value for a # of hours */
670
if(snprintf(minStr, sizeof(minStr), "RRA:MIN:%.1f:1:%d",
671
0.5, dumpHours > 0 ? dumpHours : DEFAULT_RRD_HOURS) < 0)
673
argv[argc++] = minStr;
674
if(snprintf(maxStr, sizeof(maxStr), "RRA:MAX:%.1f:1:%d",
675
0.5, dumpHours > 0 ? dumpHours : DEFAULT_RRD_HOURS) < 0)
677
argv[argc++] = maxStr;
680
if(snprintf(daysStr, sizeof(daysStr), "RRA:AVERAGE:%.1f:%d:%d",
681
0.5, value1, dumpDays * 24) < 0)
683
argv[argc++] = daysStr;
686
/* Compute the rollup - how many dumpInterval seconds interval are in a day */
687
value1 = (24*60*60 + dumpInterval - 1) / dumpInterval;
689
if(snprintf(monthsStr, sizeof(monthsStr), "RRA:AVERAGE:%.1f:%d:%d",
690
0.5, value1, dumpMonths * 30) < 0)
692
argv[argc++] = monthsStr;
695
#ifdef HAVE_RRD_ABERRANT_BEHAVIOR
696
if(snprintf(tempStr, sizeof(tempStr), "RRA:HWPREDICT:1440:0.1:0.0035:20") < 0)
698
argv[argc++] = tempStr;
702
if(shownCreate == 0) {
703
char buf[LEN_GENERAL_WORK_BUFFER];
708
memset(buf, 0, sizeof(buf));
710
if(snprintf(buf, sizeof(buf), "%s", argv[4]) < 0)
713
for (i=5; i<argc; i++) {
714
strncat(buf, " ", (sizeof(buf) - strlen(buf) - 1));
715
strncat(buf, argv[i], (sizeof(buf) - strlen(buf) - 1));
718
traceEvent(CONST_TRACE_INFO, "RRD: rrdtool create --start now-1 file %s", buf);
722
#ifdef CFG_MULTITHREADED
723
accessMutex(&rrdMutex, "rrd_create");
725
optind=0; /* reset gnu getopt */
726
opterr=0; /* no error messages */
728
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
730
rc = rrd_create(argc, argv);
732
if(rrd_test_error()) {
736
for (x = 0; x < argc; x++)
737
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: argv[%d] = %s", x, argv[x]);
740
traceEvent(CONST_TRACE_WARNING, "RRD: rrd_create(%s) error: %s", path, rrd_get_error());
745
#ifdef CFG_MULTITHREADED
746
releaseMutex(&rrdMutex);
750
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: rrd_create(%s, %s, %u)=%d",
751
hostPath, key, (unsigned long)value, rc);
758
argv[argc++] = "rrd_last";
761
#ifdef CFG_MULTITHREADED
762
accessMutex(&rrdMutex, "rrd_last");
764
optind=0; /* reset gnu getopt */
765
opterr=0; /* no error messages */
767
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
769
if(rrd_last(argc, argv) >= rrdTime) {
770
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: WARNING rrd_update not performed (RRD already updated)");
773
#ifdef CFG_MULTITHREADED
774
releaseMutex(&rrdMutex);
779
argv[argc++] = "rrd_update";
782
if((!createdCounter) && (numRuns == 1)) {
783
/* This is the first rrd update hence in order to avoid
784
wrong traffic peaks we set the value for the counter on the previous
787
# From: Alex van den Bogaerdt <alex@ergens.op.HET.NET>
788
# Date: Fri, 12 Jul 2002 01:32:45 +0200 (CEST)
789
# Subject: Re: [rrd-users] Re: To DERIVE or not to DERIVE
793
Oops. OK, so the counter is unknown. Indeed one needs to discard
794
the first interval between reboot time and poll time in that case.
798
But this would also make the next interval unknown. My suggestion:
799
insert an unknown at that time minus one second, enter the fetched
804
__________________________________________________________________
805
/ alex@slot.hollandcasino.nl alex@ergens.op.het.net \
809
if(snprintf(cmd, sizeof(cmd), "%u:u", rrdTime-10) < 0) /* u = undefined */
812
if(snprintf(cmd, sizeof(cmd), "%u:%u", rrdTime, (unsigned long)value) < 0)
818
#ifdef CFG_MULTITHREADED
819
accessMutex(&rrdMutex, "rrd_update");
821
optind=0; /* reset gnu getopt */
822
opterr=0; /* no error messages */
824
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
826
rc = rrd_update(argc, argv);
830
if(rrd_test_error()) {
835
for (x = 0; x < argc; x++)
836
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: argv[%d] = %s", x, argv[x]);
840
rrdError = rrd_get_error();
841
if(rrdError != NULL) {
842
traceEvent(CONST_TRACE_WARNING, "RRD: rrd_update(%s) error: %s", path, rrdError);
843
traceEvent(CONST_TRACE_NOISY, "RRD: call stack (counter created: %d):", createdCounter);
844
for (x = 0; x < argc; x++)
845
traceEvent(CONST_TRACE_NOISY, "RRD: argv[%d]: %s", x, argv[x]);
847
if(!strcmp(rrdError, "error: illegal attempt to update using time")) {
848
char errTimeBuf1[32], errTimeBuf2[32], errTimeBuf3[32];
852
strftime(errTimeBuf1, sizeof(errTimeBuf1), CONST_LOCALE_TIMESPEC, localtime_r(&myGlobals.actTime, &workT));
853
strftime(errTimeBuf2, sizeof(errTimeBuf2), CONST_LOCALE_TIMESPEC, localtime_r(&rrdTime, &workT));
855
argv[argc++] = "rrd_last";
858
rrdLast = rrd_last(argc, argv);
859
strftime(errTimeBuf3, sizeof(errTimeBuf3), CONST_LOCALE_TIMESPEC, localtime_r(&rrdLast, &workT));
860
traceEvent(CONST_TRACE_WARNING,
861
"RRD: actTime = %d(%s), rrdTime %d(%s), lastUpd %d(%s)",
867
rrdLast == -1 ? "rrdlast ERROR" : errTimeBuf3);
868
} else if(strstr(rrdError, "is not an RRD file")) {
876
#ifdef CFG_MULTITHREADED
877
releaseMutex(&rrdMutex);
881
/* ******************************* */
883
void updateCounter(char *hostPath, char *key, Counter value) {
884
updateRRD(hostPath, key, value, 1);
887
/* ******************************* */
889
void updateGauge(char *hostPath, char *key, Counter value) {
890
updateRRD(hostPath, key, value, 0);
893
/* ******************************* */
895
void updateTrafficCounter(char *hostPath, char *key, TrafficCounter *counter) {
896
if(counter->modified) {
897
updateCounter(hostPath, key, counter->value);
898
counter->modified = 0;
902
/* ******************************* */
904
char x2c(char *what) {
907
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
909
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
913
/* ******************************* */
915
void unescape_url(char *url) {
918
for(x=0,y=0;url[y];++x,++y) {
919
if((url[x] = url[y]) == '%') {
920
url[x] = x2c(&url[y+1]);
927
/* ******************************* */
930
static void setGlobalPermissions(int permissionsFlag) {
931
switch (permissionsFlag) {
932
case CONST_RRD_PERMISSIONS_GROUP:
933
myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_GROUP;
934
myGlobals.rrdUmask = CONST_RRD_UMASK_GROUP;
936
case CONST_RRD_PERMISSIONS_EVERYONE:
937
myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_EVERYONE;
938
myGlobals.rrdUmask = CONST_RRD_UMASK_EVERYONE;
941
myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_PRIVATE;
942
myGlobals.rrdUmask = CONST_RRD_UMASK_PRIVATE;
948
/* ******************************* */
950
static void commonRRDinit(void) {
955
if(fetchPrefsValue("rrd.dataDumpInterval", value, sizeof(value)) == -1) {
956
if(snprintf(value, sizeof(value), "%d", DEFAULT_RRD_INTERVAL) < 0)
958
storePrefsValue("rrd.dataDumpInterval", value);
959
dumpInterval = DEFAULT_RRD_INTERVAL;
961
dumpInterval = atoi(value);
964
if(fetchPrefsValue("rrd.dataDumpHours", value, sizeof(value)) == -1) {
965
if(snprintf(value, sizeof(value), "%d", DEFAULT_RRD_HOURS) < 0)
967
storePrefsValue("rrd.dataDumpHours", value);
968
dumpHours = DEFAULT_RRD_HOURS;
970
dumpHours = atoi(value);
973
if(fetchPrefsValue("rrd.dataDumpDays", value, sizeof(value)) == -1) {
974
if(snprintf(value, sizeof(value), "%d", DEFAULT_RRD_DAYS) < 0)
976
storePrefsValue("rrd.dataDumpDays", value);
977
dumpDays = DEFAULT_RRD_DAYS;
979
dumpDays = atoi(value);
982
if(fetchPrefsValue("rrd.dataDumpMonths", value, sizeof(value)) == -1) {
983
if(snprintf(value, sizeof(value), "%d", DEFAULT_RRD_MONTHS) < 0)
985
storePrefsValue("rrd.dataDumpMonths", value);
986
dumpMonths = DEFAULT_RRD_MONTHS;
988
dumpMonths = atoi(value);
991
if(fetchPrefsValue("rrd.dataDumpDomains", value, sizeof(value)) == -1) {
992
storePrefsValue("rrd.dataDumpDomains", "0");
995
dumpDomains = atoi(value);
998
if(fetchPrefsValue("rrd.dataDumpFlows", value, sizeof(value)) == -1) {
999
storePrefsValue("rrd.dataDumpFlows", "0");
1002
dumpFlows = atoi(value);
1005
if(fetchPrefsValue("rrd.dataDumpHosts", value, sizeof(value)) == -1) {
1006
storePrefsValue("rrd.dataDumpHosts", "0");
1009
dumpHosts = atoi(value);
1012
if(fetchPrefsValue("rrd.dataDumpInterfaces", value, sizeof(value)) == -1) {
1013
storePrefsValue("rrd.dataDumpInterfaces", "1");
1016
dumpInterfaces = atoi(value);
1019
if(fetchPrefsValue("rrd.dataDumpMatrix", value, sizeof(value)) == -1) {
1020
storePrefsValue("rrd.dataDumpMatrix", "0");
1023
dumpMatrix = atoi(value);
1026
if(hostsFilter != NULL) free(hostsFilter);
1027
if(fetchPrefsValue("rrd.hostsFilter", value, sizeof(value)) == -1) {
1028
storePrefsValue("rrd.hostsFilter", "");
1029
hostsFilter = strdup("");
1031
hostsFilter = strdup(value);
1034
if(fetchPrefsValue("rrd.dataDumpDetail", value, sizeof(value)) == -1) {
1035
if(snprintf(value, sizeof(value), "%d", CONST_RRD_DETAIL_DEFAULT) < 0)
1037
storePrefsValue("rrd.dataDumpDetail", value);
1038
dumpDetail = CONST_RRD_DETAIL_DEFAULT;
1040
dumpDetail = atoi(value);
1043
if(fetchPrefsValue("rrd.rrdPath", value, sizeof(value)) == -1) {
1044
char *thePath = "/rrd";
1045
int len = strlen(myGlobals.dbPath)+strlen(thePath)+1;
1047
if(myGlobals.rrdPath) free(myGlobals.rrdPath);
1048
myGlobals.rrdPath = (char*)malloc(len);
1049
if(snprintf(myGlobals.rrdPath, len, "%s%s", myGlobals.dbPath, thePath) < 0)
1051
storePrefsValue("rrd.rrdPath", myGlobals.rrdPath);
1053
int vlen = strlen(value)+1;
1055
myGlobals.rrdPath = (char*)malloc(vlen);
1056
unescape(myGlobals.rrdPath, vlen, value);
1060
if(fetchPrefsValue("rrd.permissions", value, sizeof(value)) == -1) {
1061
if(snprintf(value, sizeof(value), "%d", DEFAULT_RRD_PERMISSIONS) < 0)
1063
storePrefsValue("rrd.permissions", value);
1064
dumpPermissions = DEFAULT_RRD_PERMISSIONS;
1066
dumpPermissions = atoi(value);
1068
setGlobalPermissions(dumpPermissions);
1069
traceEvent(CONST_TRACE_INFO, "RRD: Mask for new directories is %04o",
1070
myGlobals.rrdDirectoryPermissions);
1071
umask(myGlobals.rrdUmask);
1072
traceEvent(CONST_TRACE_INFO, "RRD: Mask for new files is %04o",
1073
myGlobals.rrdUmask);
1077
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: Parameters:");
1078
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpInterval %d seconds", dumpInterval);
1079
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpHours %d hours by %d seconds", dumpHours, dumpInterval);
1080
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDays %d days by hour", dumpDays);
1081
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpMonths %d months by day", dumpMonths);
1082
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDomains %s", dumpDomains == 0 ? "no" : "yes");
1083
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpFlows %s", dumpFlows == 0 ? "no" : "yes");
1084
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpHosts %s", dumpHosts == 0 ? "no" : "yes");
1085
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpInterfaces %s", dumpInterfaces == 0 ? "no" : "yes");
1086
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpMatrix %s", dumpMatrix == 0 ? "no" : "yes");
1087
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDetail %s",
1088
dumpDetail == FLAG_RRD_DETAIL_HIGH ? "high" :
1089
(dumpDetail == FLAG_RRD_DETAIL_MEDIUM ? "medium" : "low"));
1090
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: hostsFilter %s", hostsFilter);
1091
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: rrdPath %s", myGlobals.rrdPath);
1093
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: umask %04o", myGlobals.rrdUmask);
1094
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: DirPerms %04o", myGlobals.rrdDirectoryPermissions);
1096
#endif /* RRD_DEBUG */
1101
/* ****************************** */
1103
static void handleRRDHTTPrequest(char* url) {
1104
char buf[1024], *strtokState, *mainState, *urlPiece,
1105
rrdKey[64], rrdName[64], rrdTitle[64], startTime[32], endTime[32], rrdPrefix[32];
1106
u_char action = FLAG_RRD_ACTION_NONE;
1107
int _dumpDomains, _dumpFlows, _dumpHosts, _dumpInterfaces, _dumpMatrix, _dumpDetail, _dumpInterval, _dumpHours, _dumpDays, _dumpMonths;
1108
char * _hostsFilter;
1110
int _dumpPermissions;
1113
if(initialized == 0)
1116
/* Initial values - remember, for checkboxes these need to be OFF (there's no html UNCHECKED option) */
1122
_dumpDetail=CONST_RRD_DETAIL_DEFAULT;
1123
_dumpInterval=DEFAULT_RRD_INTERVAL;
1124
_dumpHours=DEFAULT_RRD_HOURS;
1125
_dumpDays=DEFAULT_RRD_DAYS;
1126
_dumpMonths=DEFAULT_RRD_MONTHS;
1127
_hostsFilter = NULL;
1129
_dumpPermissions = DEFAULT_RRD_PERMISSIONS;
1132
if((url != NULL) && (url[0] != '\0')) {
1135
/* traceEvent(CONST_TRACE_INFO, "RRD: URL=%s", url); */
1137
urlPiece = strtok_r(url, "&", &mainState);
1138
strcpy(startTime, "now-12h");
1139
strcpy(endTime, "now");
1141
while(urlPiece != NULL) {
1144
key = strtok_r(urlPiece, "=", &strtokState);
1145
if(key != NULL) value = strtok_r(NULL, "=", &strtokState); else value = NULL;
1147
/* traceEvent(CONST_TRACE_INFO, "RRD: key(%s)=%s", key, value); */
1151
if(strcmp(key, "action") == 0) {
1152
if(strcmp(value, "graph") == 0) action = FLAG_RRD_ACTION_GRAPH;
1153
else if(strcmp(value, "list") == 0) action = FLAG_RRD_ACTION_LIST;
1154
} else if(strcmp(key, "key") == 0) {
1155
int len = strlen(value), i;
1157
if(len >= sizeof(rrdKey)) len = sizeof(rrdKey)-1;
1158
strncpy(rrdKey, value, len);
1160
for(i=0; i<len; i++) if(rrdKey[i] == '+') rrdKey[i] = ' ';
1162
if(strncmp(value, "hosts/", strlen("hosts/")) == 0) {
1164
if(snprintf(rrdPrefix, sizeof(rrdPrefix), "ip_%s_", &value[6]) < 0)
1166
plen=strlen(rrdPrefix);
1167
for (ii=0; ii<plen; ii++)
1168
if( (rrdPrefix[ii] == '.') || (rrdPrefix[ii] == '/') )
1171
rrdPrefix[0] = '\0';
1173
} else if(strcmp(key, "name") == 0) {
1174
int len = strlen(value), i;
1176
if(len >= sizeof(rrdName)) len = sizeof(rrdName)-1;
1177
strncpy(rrdName, value, len);
1178
for(i=0; i<len; i++) if(rrdName[i] == '+') rrdName[i] = ' ';
1180
rrdName[len] = '\0';
1181
} else if(strcmp(key, "title") == 0) {
1182
int len = strlen(value), i;
1184
if(len >= sizeof(rrdTitle)) len = sizeof(rrdTitle)-1;
1185
strncpy(rrdTitle, value, len);
1186
for(i=0; i<len; i++) if(rrdTitle[i] == '+') rrdTitle[i] = ' ';
1188
rrdTitle[len] = '\0';
1189
} else if(strcmp(key, "start") == 0) {
1190
int len = strlen(value);
1192
if(len >= sizeof(startTime)) len = sizeof(startTime)-1;
1193
strncpy(startTime, value, len); startTime[len] = '\0';
1194
} else if(strcmp(key, "end") == 0) {
1195
int len = strlen(value);
1197
if(len >= sizeof(endTime)) len = sizeof(endTime)-1;
1198
strncpy(endTime, value, len); endTime[len] = '\0';
1199
} else if(strcmp(key, "interval") == 0) {
1200
_dumpInterval = atoi(value);
1201
if(_dumpInterval < 1) _dumpInterval = 1 /* Min 1 second */;
1202
} else if(strcmp(key, "days") == 0) {
1203
_dumpDays = atoi(value);
1204
if(_dumpDays < 0) _dumpDays = 0 /* Min none */;
1205
} else if(strcmp(key, "hours") == 0) {
1206
_dumpHours = atoi(value);
1207
if(_dumpHours < 0) _dumpHours = 0 /* Min none */;
1208
} else if(strcmp(key, "months") == 0) {
1209
_dumpMonths = atoi(value);
1210
if(_dumpMonths < 0) _dumpMonths = 0 /* Min none */;
1211
} else if(strcmp(key, "hostsFilter") == 0) {
1212
_hostsFilter = strdup(value);
1213
} else if(strcmp(key, "rrdPath") == 0) {
1214
int vlen = strlen(value)+1;
1216
if(myGlobals.rrdPath != NULL) free(myGlobals.rrdPath);
1217
myGlobals.rrdPath = (char*)malloc(vlen);
1218
unescape(myGlobals.rrdPath, vlen, value);
1219
storePrefsValue("rrd.rrdPath", myGlobals.rrdPath);
1220
} else if(strcmp(key, "dumpDomains") == 0) {
1222
} else if(strcmp(key, "dumpFlows") == 0) {
1224
} else if(strcmp(key, "dumpDetail") == 0) {
1225
_dumpDetail = atoi(value);
1226
if(_dumpDetail > FLAG_RRD_DETAIL_HIGH) _dumpDetail = FLAG_RRD_DETAIL_HIGH;
1227
if(_dumpDetail < FLAG_RRD_DETAIL_LOW) _dumpDetail = FLAG_RRD_DETAIL_LOW;
1228
} else if(strcmp(key, "dumpHosts") == 0) {
1230
} else if(strcmp(key, "dumpInterfaces") == 0) {
1231
_dumpInterfaces = 1;
1232
} else if(strcmp(key, "dumpMatrix") == 0) {
1235
} else if(strcmp(key, "permissions") == 0) {
1236
_dumpPermissions = atoi(value);
1237
if((_dumpPermissions != CONST_RRD_PERMISSIONS_PRIVATE) &&
1238
(_dumpPermissions != CONST_RRD_PERMISSIONS_GROUP) &&
1239
(_dumpPermissions != CONST_RRD_PERMISSIONS_EVERYONE)) {
1240
_dumpPermissions = DEFAULT_RRD_PERMISSIONS;
1246
urlPiece = strtok_r(NULL, "&", &mainState);
1249
if(action == FLAG_RRD_ACTION_NONE) {
1250
dumpInterval = _dumpInterval;
1251
dumpHours = _dumpHours;
1252
dumpDays = _dumpDays;
1253
dumpMonths = _dumpMonths;
1254
/* traceEvent(CONST_TRACE_INFO, "RRD: dumpFlows=%d", dumpFlows); */
1255
dumpDomains=_dumpDomains;
1256
dumpFlows=_dumpFlows;
1257
dumpHosts=_dumpHosts;
1258
dumpInterfaces=_dumpInterfaces;
1259
dumpMatrix=_dumpMatrix;
1260
dumpDetail = _dumpDetail;
1262
dumpPermissions = _dumpPermissions;
1263
setGlobalPermissions(_dumpPermissions);
1265
if(snprintf(buf, sizeof(buf), "%d", dumpInterval) < 0)
1267
storePrefsValue("rrd.dataDumpInterval", buf);
1268
if(snprintf(buf, sizeof(buf), "%d", dumpHours) < 0)
1270
storePrefsValue("rrd.dataDumpHours", buf);
1271
if(snprintf(buf, sizeof(buf), "%d", dumpDays) < 0)
1273
storePrefsValue("rrd.dataDumpDays", buf);
1274
if(snprintf(buf, sizeof(buf), "%d", dumpMonths) < 0)
1276
storePrefsValue("rrd.dataDumpMonths", buf);
1277
if(snprintf(buf, sizeof(buf), "%d", dumpDomains) < 0)
1279
storePrefsValue("rrd.dataDumpDomains", buf);
1280
if(snprintf(buf, sizeof(buf), "%d", dumpFlows) < 0)
1282
storePrefsValue("rrd.dataDumpFlows", buf);
1283
if(snprintf(buf, sizeof(buf), "%d", dumpHosts) < 0)
1285
storePrefsValue("rrd.dataDumpHosts", buf);
1286
if(snprintf(buf, sizeof(buf), "%d", dumpInterfaces) < 0)
1288
storePrefsValue("rrd.dataDumpInterfaces", buf);
1289
if(snprintf(buf, sizeof(buf), "%d", dumpMatrix) < 0)
1291
storePrefsValue("rrd.dataDumpMatrix", buf);
1292
if(snprintf(buf, sizeof(buf), "%d", dumpDetail) < 0)
1294
storePrefsValue("rrd.dataDumpDetail", buf);
1296
if(hostsFilter != NULL) free(hostsFilter);
1297
if(_hostsFilter == NULL) {
1298
hostsFilter = strdup("");
1300
hostsFilter = _hostsFilter;
1301
_hostsFilter = NULL;
1303
storePrefsValue("rrd.hostsFilter", hostsFilter);
1305
if(snprintf(buf, sizeof(buf), "%d", dumpPermissions) < 0)
1307
storePrefsValue("rrd.permissions", buf);
1308
umask(myGlobals.rrdUmask);
1310
traceEvent(CONST_TRACE_INFO, "RRD: Mask for new directories set to %04o",
1311
myGlobals.rrdDirectoryPermissions);
1312
traceEvent(CONST_TRACE_INFO, "RRD: Mask for new files set to %04o",
1313
myGlobals.rrdUmask);
1320
if(_hostsFilter != NULL) free(_hostsFilter);
1322
/* traceEvent(CONST_TRACE_INFO, "RRD: action=%d", action); */
1324
if(action == FLAG_RRD_ACTION_GRAPH) {
1325
graphCounter(rrdKey, rrdName, rrdTitle, startTime, endTime, rrdPrefix);
1327
} else if(action == FLAG_RRD_ACTION_LIST) {
1328
listResource(rrdKey, rrdTitle, startTime, endTime);
1332
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
1333
printHTMLheader("RRD Preferences", NULL, 0);
1336
sendString("<p>You must restart the rrd plugin for changes here to take affect.</p>\n");
1338
sendString("<p>Changes here will take effect when the plugin is started.</p>\n");
1340
sendString("<center><form action=\"/plugins/rrdPlugin\" method=GET>\n"
1341
"<TABLE BORDER=1 "TABLE_DEFAULTS">\n"
1342
"<TR><TH ALIGN=CENTER "DARK_BG">Item</TH>"
1343
"<TH ALIGN=CENTER "DARK_BG">Description and notes</TH></TR>\n"
1344
"<TR><TH ALIGN=LEFT "DARK_BG">Dump Interval</TH><TD>"
1345
"<INPUT NAME=interval SIZE=5 VALUE=");
1346
if(snprintf(buf, sizeof(buf), "%d", (int)dumpInterval) < 0)
1349
sendString("> seconds<br>Specifies how often data is stored permanently.</TD></tr>\n");
1351
sendString("<TR><TH ALIGN=LEFT "DARK_BG">Dump Hours</TH><TD>"
1352
"<INPUT NAME=hours SIZE=5 VALUE=");
1353
if(snprintf(buf, sizeof(buf), "%d", (int)dumpHours) < 0)
1356
sendString("><br>Specifies how many hours of 'interval' data is stored permanently.</TD></tr>\n");
1358
sendString("<TR><TH ALIGN=LEFT "DARK_BG">Dump Days</TH><TD>"
1359
"<INPUT NAME=days SIZE=5 VALUE=");
1360
if(snprintf(buf, sizeof(buf), "%d", (int)dumpDays) < 0)
1363
sendString("><br>Specifies how many days of hourly data is stored permanently.</TD></tr>\n");
1364
sendString("<TR><TH ALIGN=LEFT "DARK_BG">Dump Months</TH><TD>"
1365
"<INPUT NAME=months SIZE=5 VALUE=");
1366
if(snprintf(buf, sizeof(buf), "%d", (int)dumpMonths) < 0)
1369
sendString("><br>Specifies how many months of daily data is stored permanently.</TD></tr>\n");
1371
sendString("<TR><TD ALIGN=CENTER COLSPAN=2><B>WARNING:</B> "
1372
"Changes to the above values will ONLY affect NEW rrds</TD></TR>");
1374
sendString("<TR><TH ALIGN=LEFT "DARK_BG">Data to Dump</TH><TD>");
1376
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpDomains VALUE=1 %s> Domains<br>\n",
1377
dumpDomains ? "CHECKED" : "" ) < 0)
1381
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpFlows VALUE=1 %s> Flows<br>\n",
1382
dumpFlows ? "CHECKED" : "" ) < 0)
1386
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpHosts VALUE=1 %s> Hosts<br>\n",
1387
dumpHosts ? "CHECKED" : "") < 0)
1391
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpInterfaces VALUE=1 %s> Interfaces<br>\n",
1392
dumpInterfaces ? "CHECKED" : "") < 0)
1396
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpMatrix VALUE=1 %s> Matrix<br>\n",
1397
dumpMatrix ? "CHECKED" : "") < 0)
1401
sendString("</TD></tr>\n");
1404
sendString("<TR><TH ALIGN=LEFT "DARK_BG">Hosts Filter</TH><TD>"
1405
"<INPUT NAME=hostsFilter VALUE=\"");
1407
sendString(hostsFilter);
1409
sendString("\" SIZE=80><br>A list of networks [e.g. 172.22.0.0/255.255.0.0,192.168.5.0/255.255.255.0]<br>"
1410
"separated by commas to which hosts that will be<br>"
1411
"saved must belong to. An empty list means that all the hosts will "
1412
"be stored on disk</TD></tr>\n");
1415
sendString("<TR><TH ALIGN=LEFT "DARK_BG">RRD Detail</TH><TD>");
1416
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=radio NAME=dumpDetail VALUE=%d %s>Low\n",
1417
FLAG_RRD_DETAIL_LOW, (dumpDetail == FLAG_RRD_DETAIL_LOW) ? "CHECKED" : "") < 0)
1421
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=radio NAME=dumpDetail VALUE=%d %s>Medium\n",
1422
FLAG_RRD_DETAIL_MEDIUM, (dumpDetail == FLAG_RRD_DETAIL_MEDIUM) ? "CHECKED" : "") < 0)
1426
if(snprintf(buf, sizeof(buf), "<INPUT TYPE=radio NAME=dumpDetail VALUE=%d %s>Full\n",
1427
FLAG_RRD_DETAIL_HIGH, (dumpDetail == FLAG_RRD_DETAIL_HIGH) ? "CHECKED" : "") < 0)
1430
sendString("</TD></TR>\n");
1432
sendString("<TR><TH ALIGN=LEFT "DARK_BG">RRD Files Path</TH><TD>"
1433
"<INPUT NAME=rrdPath SIZE=50 VALUE=\"");
1434
sendString(myGlobals.rrdPath);
1436
sendString("<br>NOTE: The rrd files will be in a subdirectory structure, e.g.\n");
1437
if(snprintf(buf, sizeof(buf),
1439
"%s\\interfaces\\interface-name\\12\\239\\98\\199\\xxxxx.rrd ",
1441
"%s/interfaces/interface-name/12/239/98/199/xxxxx.rrd ",
1443
myGlobals.rrdPath) < 0)
1446
sendString("to limit the number of files per subdirectory.");
1447
sendString("</TD></tr>\n");
1449
sendString("<TR><TH ALIGN=LEFT "DARK_BG">RRD Updates</TH><TD>");
1450
if(snprintf(buf, sizeof(buf), "%lu RRD files updated</TD></TR>\n", (unsigned long)numTotalRRDs) < 0)
1454
sendString("<TR><TH ALIGN=LEFT "DARK_BG">RRD Update Errors</TH><TD>");
1455
if(snprintf(buf, sizeof(buf), "%lu RRD update errors</TD></TR>\n", (unsigned long)numRRDerrors) < 0)
1459
sendString("<TR><TH ALIGN=LEFT "DARK_BG">RRD Graphic Requests</TH><TD>");
1460
if(snprintf(buf, sizeof(buf), "%lu RRD graphics requested</TD></TR>\n",
1461
(unsigned long)rrdGraphicRequests) < 0)
1466
sendString("<TR><TH ALIGN=LEFT "DARK_BG">File/Directory Permissions</TH><TD>");
1467
sendString("<ul>\n");
1468
if(snprintf(buf, sizeof(buf), "<li><INPUT TYPE=radio NAME=permissions VALUE=%d %s>Private - ",
1469
CONST_RRD_PERMISSIONS_PRIVATE,
1470
(dumpPermissions == CONST_RRD_PERMISSIONS_PRIVATE) ? "CHECKED" : "") < 0)
1473
sendString("means that ONLY the ntop userid will be able to view the files</li>\n");
1475
if(snprintf(buf, sizeof(buf), "<li><INPUT TYPE=radio NAME=permissions VALUE=%d %s>Group - ",
1476
CONST_RRD_PERMISSIONS_GROUP,
1477
(dumpPermissions == CONST_RRD_PERMISSIONS_GROUP) ? "CHECKED" : "") < 0)
1480
sendString("means that all users in the same group as the ntop userid will be able to view the rrd files.\n");
1481
sendString("<br><i>(this is a bad choice if ntop's group is 'nobody' along with many other service ids)</i></li>\n");
1483
if(snprintf(buf, sizeof(buf), "<li><INPUT TYPE=radio NAME=permissions VALUE=%d %s>Everyone - ",
1484
CONST_RRD_PERMISSIONS_EVERYONE,
1485
(dumpPermissions == CONST_RRD_PERMISSIONS_EVERYONE) ? "CHECKED" : "") < 0)
1488
sendString("means that everyone on the ntop host system will be able to view the rrd files.</li>\n");
1490
sendString("</ul><br>\n<B>WARNING</B>: Changing this setting affects only new files "
1492
"<i>Unless you go back and fixup existing file and directory permissions:</i><br>\n"
1493
"<ul><li>Users will retain access to any rrd file or directory they currently have "
1494
"access to even if you change to a more restrictive setting.</li>\n"
1495
"<li>Users will not gain access to any rrd file or directory they currently do not "
1496
"have access to even if you change to a less restrictive setting. Further, existing "
1497
"directory permissions may prevent them from reading new files created in existing "
1498
"directories.</li>\n"
1499
"</ul>\n</TD></TR>\n");
1502
sendString("<tr><td colspan=\"2\" align=\"center\">"
1503
"<input type=submit value=\"Save Preferences\"></td></tr></table>\n"
1504
"</form>\n<p></center>\n");
1507
printPluginTrailer(NULL,
1508
"<a href=\"http://www.rrdtool.org/\" title=\"rrd home page\">RRDtool</a> "
1510
"<a href=\"http://ee-staff.ethz.ch/~oetiker/\" title=\"Tobi's home page\">"
1511
"Tobi Oetiker</a>");
1516
/* ****************************** */
1517
#ifdef MAKE_WITH_RRDSIGTRAP
1518
RETSIGTYPE rrdcleanup(int signo) {
1519
static int msgSent = 0;
1526
traceEvent(CONST_TRACE_FATALERROR, "RRD: caught signal %d %s", signo,
1527
signo == SIGHUP ? "SIGHUP" :
1528
signo == SIGINT ? "SIGINT" :
1529
signo == SIGQUIT ? "SIGQUIT" :
1530
signo == SIGILL ? "SIGILL" :
1531
signo == SIGABRT ? "SIGABRT" :
1532
signo == SIGFPE ? "SIGFPE" :
1533
signo == SIGKILL ? "SIGKILL" :
1534
signo == SIGSEGV ? "SIGSEGV" :
1535
signo == SIGPIPE ? "SIGPIPE" :
1536
signo == SIGALRM ? "SIGALRM" :
1537
signo == SIGTERM ? "SIGTERM" :
1538
signo == SIGUSR1 ? "SIGUSR1" :
1539
signo == SIGUSR2 ? "SIGUSR2" :
1540
signo == SIGCHLD ? "SIGCHLD" :
1542
signo == SIGCONT ? "SIGCONT" :
1545
signo == SIGSTOP ? "SIGSTOP" :
1548
signo == SIGBUS ? "SIGBUS" :
1551
signo == SIGSYS ? "SIGSYS"
1557
#ifdef HAVE_BACKTRACE
1558
/* Don't double fault... */
1559
/* signal(signo, SIG_DFL); */
1561
/* Grab the backtrace before we do much else... */
1562
size = backtrace(array, 20);
1563
strings = (char**)backtrace_symbols(array, size);
1565
traceEvent(CONST_TRACE_FATALERROR, "RRD: BACKTRACE: backtrace is:");
1567
traceEvent(CONST_TRACE_FATALERROR, "RRD: BACKTRACE: **unavailable!");
1569
/* Ignore the 0th entry, that's our cleanup() */
1570
for (i=1; i<size; i++) {
1571
traceEvent(CONST_TRACE_FATALERROR, "RRD: BACKTRACE: %2d. %s", i, strings[i]);
1574
#endif /* HAVE_BACKTRACE */
1578
#endif /* MAKE_WITH_RRDSIGTRAP */
1580
/* ****************************** */
1582
static void* rrdMainLoop(void* notUsed _UNUSED_) {
1583
char value[512 /* leave it big for hosts filter */];
1584
u_int32_t networks[32][3];
1585
u_short numLocalNets;
1586
int sleep_tm, devIdx, idx;
1590
ProtocolsList *protoList;
1592
#ifdef CFG_MULTITHREADED
1593
traceEvent(CONST_TRACE_INFO, "THREADMGMT: rrd thread (%ld) started", rrdThread);
1596
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: rrdMainLoop()");
1600
#ifdef MAKE_WITH_RRDSIGTRAP
1601
signal(SIGSEGV, rrdcleanup);
1602
signal(SIGHUP, rrdcleanup);
1603
signal(SIGINT, rrdcleanup);
1604
signal(SIGQUIT, rrdcleanup);
1605
signal(SIGILL, rrdcleanup);
1606
signal(SIGABRT, rrdcleanup);
1607
signal(SIGFPE, rrdcleanup);
1608
signal(SIGKILL, rrdcleanup);
1609
signal(SIGPIPE, rrdcleanup);
1610
signal(SIGALRM, rrdcleanup);
1611
signal(SIGTERM, rrdcleanup);
1612
signal(SIGUSR1, rrdcleanup);
1613
signal(SIGUSR2, rrdcleanup);
1614
/* signal(SIGCHLD, rrdcleanup); */
1616
signal(SIGCONT, rrdcleanup);
1619
signal(SIGSTOP, rrdcleanup);
1622
signal(SIGBUS, rrdcleanup);
1625
signal(SIGSYS, rrdcleanup);
1627
#endif /* MAKE_WITH_RRDSIGTRAP */
1629
if(initialized == 0)
1632
/* Initialize the "end" of the dummy interval just far enough back in time
1633
so that it expires once everything is up and running. */
1634
end_tm = myGlobals.actTime - dumpInterval + 15;
1636
/* Show we're running */
1639
for(;myGlobals.capturePackets != FLAG_NTOPSTATE_TERM;) {
1642
Counter numRRDs = numTotalRRDs;
1651
end_tm += dumpInterval;
1652
sleep_tm = end_tm - (start_tm = time(NULL));
1653
} while (sleep_tm < 0);
1658
strftime(endTime, sizeof(endTime), CONST_LOCALE_TIMESPEC, localtime_r(&end_tm, &workT));
1659
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: Sleeping for %d seconds (interval %d, end at %s)",
1666
HEARTBEAT(0, "rrdMainLoop(), sleep(%d)...", sleep_tm);
1668
HEARTBEAT(0, "rrdMainLoop(), sleep(%d)...woke", sleep_tm);
1669
if(myGlobals.capturePackets != FLAG_NTOPSTATE_RUN) return(NULL);
1672
rrdTime = time(NULL);
1674
/* ****************************************************** */
1677
/* Avoids strtok to blanks into hostsFilter */
1678
if(snprintf(rrdPath, sizeof(rrdPath), "%s", hostsFilter) < 0)
1680
handleAddressLists(rrdPath, networks, &numLocalNets, value, sizeof(value), CONST_HANDLEADDRESSLISTS_RRD);
1682
/* ****************************************************** */
1686
DomainStats **stats, *tmpStats, *statsEntry;
1687
u_int maxHosts, len = 0;
1688
Counter totBytesSent = 0;
1689
Counter totBytesRcvd = 0;
1693
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
1694
u_int numEntries = 0;
1696
// save this as it may change
1697
maxHosts = myGlobals.device[devIdx].hostsno;
1698
len = sizeof(DomainStats)*maxHosts;
1699
tmpStats = (DomainStats*)malloc(len);
1700
memset(tmpStats, 0, len);
1702
len = sizeof(DomainStats**)*maxHosts;
1703
stats = (DomainStats**)malloc(len);
1704
memset(stats, 0, len);
1706
// walk through all hosts, getting their domain names and counting stats
1707
for (el = getFirstHost(devIdx);
1708
el != NULL; el = getNextHost(devIdx, el)) {
1712
// if we didn't get a domain name, bail out
1713
if ((el->dnsDomainValue == NULL)
1714
|| (el->dnsDomainValue[0] == '\0')
1715
|| (el->ip2ccValue == NULL)
1716
|| (el->hostResolvedName[0] == '\0')
1717
|| broadcastHost(el)
1722
for(keyValue=0, idx=0; el->dnsDomainValue[idx] != '\0'; idx++)
1723
keyValue += (idx+1)*(u_short)el->dnsDomainValue[idx];
1725
keyValue %= maxHosts;
1727
while((stats[keyValue] != NULL)
1728
&& (strcasecmp(stats[keyValue]->domainHost->dnsDomainValue,
1729
el->dnsDomainValue) != 0))
1730
keyValue = (keyValue+1) % maxHosts;
1732
// if we just start counting for this domain...
1733
if(stats[keyValue] != NULL)
1734
statsEntry = stats[keyValue];
1736
statsEntry = &tmpStats[numEntries++];
1737
memset(statsEntry, 0, sizeof(DomainStats));
1738
statsEntry->domainHost = el;
1739
stats[keyValue] = statsEntry;
1741
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG [%d] %s/%s", numEntries, el->dnsDomainValue, el->ip2ccValue);
1745
// count this host's stats in the domain stats
1746
totBytesSent += el->bytesSent.value;
1747
statsEntry->bytesSent.value += el->bytesSent.value;
1748
statsEntry->bytesRcvd.value += el->bytesRcvd.value;
1749
totBytesRcvd += el->bytesRcvd.value;
1750
statsEntry->tcpSent.value += el->tcpSentLoc.value + el->tcpSentRem.value;
1751
statsEntry->udpSent.value += el->udpSentLoc.value + el->udpSentRem.value;
1752
statsEntry->icmpSent.value += el->icmpSent.value;
1753
statsEntry->icmp6Sent.value += el->icmp6Sent.value;
1754
statsEntry->tcpRcvd.value += el->tcpRcvdLoc.value + el->tcpRcvdFromRem.value;
1755
statsEntry->udpRcvd.value += el->udpRcvdLoc.value + el->udpRcvdFromRem.value;
1756
statsEntry->icmpRcvd.value += el->icmpRcvd.value;
1757
statsEntry->icmp6Rcvd.value += el->icmp6Rcvd.value;
1759
if(numEntries >= maxHosts) break;
1762
// if we didn't find a single domain, continue with the next interface
1763
if (numEntries == 0) {
1764
free(tmpStats); free(stats);
1768
// insert all domain data for this interface into the RRDs
1769
for (idx=0; idx < numEntries; idx++) {
1770
statsEntry = &tmpStats[idx];
1772
if(snprintf(rrdPath, sizeof(rrdPath), "%s/interfaces/%s/domains/%s/",
1773
myGlobals.rrdPath, myGlobals.device[devIdx].humanFriendlyName,
1774
statsEntry->domainHost->dnsDomainValue) < 0)
1779
traceEvent(CONST_TRACE_INFO, "RRD: Updating %s", rrdPath);
1781
updateCounter(rrdPath, "bytesSent", statsEntry->bytesSent.value);
1782
updateCounter(rrdPath, "bytesRcvd", statsEntry->bytesRcvd.value);
1784
updateCounter(rrdPath, "tcpSent", statsEntry->tcpSent.value);
1785
updateCounter(rrdPath, "udpSent", statsEntry->udpSent.value);
1786
updateCounter(rrdPath, "icmpSent", statsEntry->icmpSent.value);
1787
updateCounter(rrdPath, "icmp6Sent", statsEntry->icmp6Sent.value);
1789
updateCounter(rrdPath, "tcpRcvd", statsEntry->tcpRcvd.value);
1790
updateCounter(rrdPath, "udpRcvd", statsEntry->udpRcvd.value);
1791
updateCounter(rrdPath, "icmpRcvd", statsEntry->icmpRcvd.value);
1792
updateCounter(rrdPath, "icmp6Rcvd", statsEntry->icmp6Rcvd.value);
1795
free(tmpStats); free(stats);
1799
/* ****************************************************** */
1802
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
1803
for(i=1; i<myGlobals.device[devIdx].actualHashSize; i++) {
1804
HostTraffic *el = myGlobals.device[devIdx].hash_hostTraffic[i];
1807
if((el == myGlobals.otherHostEntry) || (el == myGlobals.broadcastEntry)
1808
|| broadcastHost(el) || (myGlobals.trackOnlyLocalHosts && (!subnetPseudoLocalHost(el)))) {
1813
#ifdef CFG_MULTITHREADED
1814
accessMutex(&myGlobals.hostsHashMutex, "rrdDumpHosts");
1817
if((el->bytesSent.value > 0) || (el->bytesRcvd.value > 0)) {
1818
if(el->hostNumIpAddress[0] != '\0') {
1819
hostKey = el->hostNumIpAddress;
1821
if((numLocalNets > 0)
1822
&& (el->hostIpAddress.hostFamily == AF_INET) /* IPv4 ONLY <-- FIX */
1823
&& (!__pseudoLocalAddress(&el->hostIpAddress.Ip4Address, networks, numLocalNets))) {
1825
#ifdef CFG_MULTITHREADED
1826
releaseMutex(&myGlobals.hostsHashMutex);
1831
if((!myGlobals.dontTrustMACaddr)
1832
&& subnetPseudoLocalHost(el)
1833
&& (el->ethAddressString[0] != '\0')) /*
1835
MAC address is empty even
1836
for local hosts if this host has
1837
been learnt on a virtual interface
1838
such as the NetFlow interface
1840
hostKey = el->ethAddressString;
1842
/* For the time being do not save IP-less hosts */
1845
#ifdef CFG_MULTITHREADED
1846
releaseMutex(&myGlobals.hostsHashMutex);
1851
adjHostName = dotToSlash(hostKey);
1853
if(snprintf(rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/",
1854
myGlobals.rrdPath, myGlobals.device[devIdx].humanFriendlyName,
1860
traceEvent(CONST_TRACE_INFO, "RRD: Updating %s [%s/%s]",
1861
hostKey, el->hostNumIpAddress, el->ethAddressString);
1864
updateTrafficCounter(rrdPath, "pktSent", &el->pktSent);
1865
updateTrafficCounter(rrdPath, "pktRcvd", &el->pktRcvd);
1866
updateTrafficCounter(rrdPath, "bytesSent", &el->bytesSent);
1867
updateTrafficCounter(rrdPath, "bytesRcvd", &el->bytesRcvd);
1869
if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) {
1870
updateTrafficCounter(rrdPath, "pktDuplicatedAckSent", &el->pktDuplicatedAckSent);
1871
updateTrafficCounter(rrdPath, "pktDuplicatedAckRcvd", &el->pktDuplicatedAckRcvd);
1872
updateTrafficCounter(rrdPath, "pktBroadcastSent", &el->pktBroadcastSent);
1873
updateTrafficCounter(rrdPath, "bytesBroadcastSent", &el->bytesBroadcastSent);
1874
updateTrafficCounter(rrdPath, "pktMulticastSent", &el->pktMulticastSent);
1875
updateTrafficCounter(rrdPath, "bytesMulticastSent", &el->bytesMulticastSent);
1876
updateTrafficCounter(rrdPath, "pktMulticastRcvd", &el->pktMulticastRcvd);
1877
updateTrafficCounter(rrdPath, "bytesMulticastRcvd", &el->bytesMulticastRcvd);
1879
updateTrafficCounter(rrdPath, "bytesSentLoc", &el->bytesSentLoc);
1880
updateTrafficCounter(rrdPath, "bytesSentRem", &el->bytesSentRem);
1881
updateTrafficCounter(rrdPath, "bytesRcvdLoc", &el->bytesRcvdLoc);
1882
updateTrafficCounter(rrdPath, "bytesRcvdFromRem", &el->bytesRcvdFromRem);
1883
updateTrafficCounter(rrdPath, "ipBytesSent", &el->ipBytesSent);
1884
updateTrafficCounter(rrdPath, "ipBytesRcvd", &el->ipBytesRcvd);
1885
updateTrafficCounter(rrdPath, "tcpSentLoc", &el->tcpSentLoc);
1886
updateTrafficCounter(rrdPath, "tcpSentRem", &el->tcpSentRem);
1887
updateTrafficCounter(rrdPath, "udpSentLoc", &el->udpSentLoc);
1888
updateTrafficCounter(rrdPath, "udpSentRem", &el->udpSentRem);
1889
updateTrafficCounter(rrdPath, "icmpSent", &el->icmpSent);
1890
updateTrafficCounter(rrdPath, "tcpRcvdLoc", &el->tcpRcvdLoc);
1891
updateTrafficCounter(rrdPath, "tcpRcvdFromRem", &el->tcpRcvdFromRem);
1892
updateTrafficCounter(rrdPath, "udpRcvdLoc", &el->udpRcvdLoc);
1893
updateTrafficCounter(rrdPath, "udpRcvdFromRem", &el->udpRcvdFromRem);
1894
updateTrafficCounter(rrdPath, "icmpRcvd", &el->icmpRcvd);
1895
updateTrafficCounter(rrdPath, "tcpFragmentsSent", &el->tcpFragmentsSent);
1896
updateTrafficCounter(rrdPath, "tcpFragmentsRcvd", &el->tcpFragmentsRcvd);
1897
updateTrafficCounter(rrdPath, "udpFragmentsSent", &el->udpFragmentsSent);
1898
updateTrafficCounter(rrdPath, "udpFragmentsRcvd", &el->udpFragmentsRcvd);
1899
updateTrafficCounter(rrdPath, "icmpFragmentsSent", &el->icmpFragmentsSent);
1900
updateTrafficCounter(rrdPath, "icmpFragmentsRcvd", &el->icmpFragmentsRcvd);
1901
updateTrafficCounter(rrdPath, "stpSent", &el->stpSent);
1902
updateTrafficCounter(rrdPath, "stpRcvd", &el->stpRcvd);
1903
updateTrafficCounter(rrdPath, "ipxSent", &el->ipxSent);
1904
updateTrafficCounter(rrdPath, "ipxRcvd", &el->ipxRcvd);
1905
updateTrafficCounter(rrdPath, "osiSent", &el->osiSent);
1906
updateTrafficCounter(rrdPath, "osiRcvd", &el->osiRcvd);
1907
updateTrafficCounter(rrdPath, "dlcSent", &el->dlcSent);
1908
updateTrafficCounter(rrdPath, "dlcRcvd", &el->dlcRcvd);
1909
updateTrafficCounter(rrdPath, "arp_rarpSent", &el->arp_rarpSent);
1910
updateTrafficCounter(rrdPath, "arp_rarpRcvd", &el->arp_rarpRcvd);
1911
updateTrafficCounter(rrdPath, "arpReqPktsSent", &el->arpReqPktsSent);
1912
updateTrafficCounter(rrdPath, "arpReplyPktsSent", &el->arpReplyPktsSent);
1913
updateTrafficCounter(rrdPath, "arpReplyPktsRcvd", &el->arpReplyPktsRcvd);
1914
updateTrafficCounter(rrdPath, "decnetSent", &el->decnetSent);
1915
updateTrafficCounter(rrdPath, "decnetRcvd", &el->decnetRcvd);
1916
updateTrafficCounter(rrdPath, "appletalkSent", &el->appletalkSent);
1917
updateTrafficCounter(rrdPath, "appletalkRcvd", &el->appletalkRcvd);
1918
updateTrafficCounter(rrdPath, "netbiosSent", &el->netbiosSent);
1919
updateTrafficCounter(rrdPath, "netbiosRcvd", &el->netbiosRcvd);
1920
updateTrafficCounter(rrdPath, "ipv6Sent", &el->ipv6Sent);
1921
updateTrafficCounter(rrdPath, "ipv6Rcvd", &el->ipv6Rcvd);
1922
updateTrafficCounter(rrdPath, "otherSent", &el->otherSent);
1923
updateTrafficCounter(rrdPath, "otherRcvd", &el->otherRcvd);
1925
protoList = myGlobals.ipProtosList, idx=0;
1926
while(protoList != NULL) {
1929
if(snprintf(buf, sizeof(buf), "%sSent", protoList->protocolName) < 0) BufferTooShort();
1930
updateTrafficCounter(rrdPath, buf, &el->ipProtosList[idx].sent);
1931
if(snprintf(buf, sizeof(buf), "%sRcvd", protoList->protocolName) < 0) BufferTooShort();
1932
updateTrafficCounter(rrdPath, buf, &el->ipProtosList[idx].rcvd);
1933
idx++, protoList = protoList->next;
1937
if(dumpDetail == FLAG_RRD_DETAIL_HIGH) {
1938
updateCounter(rrdPath, "totContactedSentPeers", el->totContactedSentPeers);
1939
updateCounter(rrdPath, "totContactedRcvdPeers", el->totContactedRcvdPeers);
1941
if((hostKey == el->hostNumIpAddress) && el->protoIPTrafficInfos) {
1943
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: Updating host %s", hostKey);
1946
if(snprintf(rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/IP_",
1948
myGlobals.device[devIdx].humanFriendlyName,
1953
for(j=0; j<myGlobals.numIpProtosToMonitor; j++) {
1955
if(snprintf(key, sizeof(key), "%sSentBytes",
1956
myGlobals.protoIPTrafficInfos[j]) < 0)
1958
updateCounter(rrdPath, key, el->protoIPTrafficInfos[j].sentLoc.value+
1959
el->protoIPTrafficInfos[j].sentRem.value);
1961
if(snprintf(key, sizeof(key), "%sRcvdBytes",
1962
myGlobals.protoIPTrafficInfos[j]) < 0)
1964
updateCounter(rrdPath, key, el->protoIPTrafficInfos[j].rcvdLoc.value+
1965
el->protoIPTrafficInfos[j].rcvdFromRem.value);
1970
if(adjHostName != NULL)
1974
#ifdef CFG_MULTITHREADED
1975
releaseMutex(&myGlobals.hostsHashMutex);
1977
#ifdef MAKE_WITH_SCHED_YIELD
1978
sched_yield(); /* Allow other threads to run */
1983
} /* for(devIdx...) */
1986
/* ************************** */
1989
FlowFilterList *list = myGlobals.flowsList;
1991
while(list != NULL) {
1992
if(list->pluginStatus.activePlugin) {
1993
if(snprintf(rrdPath, sizeof(rrdPath), "%s/flows/%s/",
1994
myGlobals.rrdPath, list->flowName) < 0)
1998
updateCounter(rrdPath, "packets", list->packets.value);
1999
updateCounter(rrdPath, "bytes", list->bytes.value);
2006
/* ************************** */
2008
if(dumpInterfaces) {
2009
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
2011
if(myGlobals.device[devIdx].virtualDevice) continue;
2013
if(snprintf(rrdPath, sizeof(rrdPath), "%s/interfaces/%s/", myGlobals.rrdPath,
2014
myGlobals.device[devIdx].humanFriendlyName) < 0)
2018
updateCounter(rrdPath, "ethernetPkts", myGlobals.device[devIdx].ethernetPkts.value);
2019
updateCounter(rrdPath, "broadcastPkts", myGlobals.device[devIdx].broadcastPkts.value);
2020
updateCounter(rrdPath, "multicastPkts", myGlobals.device[devIdx].multicastPkts.value);
2021
updateCounter(rrdPath, "ethernetBytes", myGlobals.device[devIdx].ethernetBytes.value);
2022
updateGauge(rrdPath, "knownHostsNum", myGlobals.device[devIdx].hostsno);
2023
updateGauge(rrdPath, "activeHostSendersNum", numActiveSenders(devIdx));
2024
updateCounter(rrdPath, "ipBytes", myGlobals.device[devIdx].ipBytes.value);
2026
if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) {
2027
updateCounter(rrdPath, "droppedPkts", myGlobals.device[devIdx].droppedPkts.value);
2028
updateCounter(rrdPath, "fragmentedIpBytes", myGlobals.device[devIdx].fragmentedIpBytes.value);
2029
updateCounter(rrdPath, "tcpBytes", myGlobals.device[devIdx].tcpBytes.value);
2030
updateCounter(rrdPath, "udpBytes", myGlobals.device[devIdx].udpBytes.value);
2031
updateCounter(rrdPath, "otherIpBytes", myGlobals.device[devIdx].otherIpBytes.value);
2032
updateCounter(rrdPath, "icmpBytes", myGlobals.device[devIdx].icmpBytes.value);
2033
updateCounter(rrdPath, "dlcBytes", myGlobals.device[devIdx].dlcBytes.value);
2034
updateCounter(rrdPath, "ipxBytes", myGlobals.device[devIdx].ipxBytes.value);
2035
updateCounter(rrdPath, "stpBytes", myGlobals.device[devIdx].stpBytes.value);
2036
updateCounter(rrdPath, "decnetBytes", myGlobals.device[devIdx].decnetBytes.value);
2037
updateCounter(rrdPath, "netbiosBytes", myGlobals.device[devIdx].netbiosBytes.value);
2038
updateCounter(rrdPath, "arpRarpBytes", myGlobals.device[devIdx].arpRarpBytes.value);
2039
updateCounter(rrdPath, "atalkBytes", myGlobals.device[devIdx].atalkBytes.value);
2040
updateCounter(rrdPath, "egpBytes", myGlobals.device[devIdx].egpBytes.value);
2041
updateCounter(rrdPath, "osiBytes", myGlobals.device[devIdx].osiBytes.value);
2042
updateCounter(rrdPath, "ipv6Bytes", myGlobals.device[devIdx].ipv6Bytes.value);
2043
updateCounter(rrdPath, "otherBytes", myGlobals.device[devIdx].otherBytes.value);
2044
updateCounter(rrdPath, "upTo64Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo64.value);
2045
updateCounter(rrdPath, "upTo128Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo128.value);
2046
updateCounter(rrdPath, "upTo256Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo256.value);
2047
updateCounter(rrdPath, "upTo512Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo512.value);
2048
updateCounter(rrdPath, "upTo1024Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo1024.value);
2049
updateCounter(rrdPath, "upTo1518Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo1518.value);
2050
updateCounter(rrdPath, "badChecksumPkts", myGlobals.device[devIdx].rcvdPktStats.badChecksum.value);
2051
updateCounter(rrdPath, "tooLongPkts", myGlobals.device[devIdx].rcvdPktStats.tooLong.value);
2053
protoList = myGlobals.ipProtosList, idx=0;
2054
while(protoList != NULL) {
2055
updateCounter(rrdPath, protoList->protocolName, myGlobals.device[devIdx].ipProtosList[idx].value);
2056
idx++, protoList = protoList->next;
2060
if(dumpDetail == FLAG_RRD_DETAIL_HIGH) {
2061
if(myGlobals.device[devIdx].ipProtoStats != NULL) {
2062
if(snprintf(rrdPath, sizeof(rrdPath), "%s/interfaces/%s/IP_",
2063
myGlobals.rrdPath, myGlobals.device[devIdx].humanFriendlyName) < 0)
2066
for(j=0; j<myGlobals.numIpProtosToMonitor; j++) {
2071
myGlobals.device[devIdx].ipProtoStats[j].local.value+
2072
myGlobals.device[devIdx].ipProtoStats[j].local2remote.value+
2073
myGlobals.device[devIdx].ipProtoStats[j].remote2local.value+
2074
myGlobals.device[devIdx].ipProtoStats[j].remote.value;
2076
if(snprintf(tmpStr, sizeof(tmpStr), "%sBytes", myGlobals.protoIPTrafficInfos[j]) < 0)
2078
updateCounter(rrdPath, tmpStr, ctr.value);
2085
/* ************************** */
2090
for(k=0; k<myGlobals.numDevices; k++)
2091
for(i=1; i<myGlobals.device[k].numHosts; i++)
2092
for(j=1; j<myGlobals.device[k].numHosts; j++) {
2094
idx = i*myGlobals.device[k].numHosts+j;
2096
if(myGlobals.device[k].ipTrafficMatrix == NULL)
2098
if(myGlobals.device[k].ipTrafficMatrix[idx] == NULL)
2101
if(myGlobals.device[k].ipTrafficMatrix[idx]->bytesSent.value > 0) {
2103
if(snprintf(rrdPath, sizeof(rrdPath), "%s/interfaces/%s/matrix/%s/%s/",
2105
myGlobals.device[k].humanFriendlyName,
2106
myGlobals.device[k].ipTrafficMatrixHosts[i]->hostNumIpAddress,
2107
myGlobals.device[k].ipTrafficMatrixHosts[j]->hostNumIpAddress) < 0)
2111
updateCounter(rrdPath, "pkts",
2112
myGlobals.device[k].ipTrafficMatrix[idx]->pktsSent.value);
2114
updateCounter(rrdPath, "bytes",
2115
myGlobals.device[k].ipTrafficMatrix[idx]->bytesSent.value);
2122
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: %lu RRDs updated (%lu total updates)",
2123
(unsigned long)(numTotalRRDs-numRRDs), (unsigned long)numTotalRRDs);
2127
* If it's FLAG_NTOPSTATE_STOPCAP, and we're still running, then this
2128
* is the 1st pass. We just updated our data to save the counts, now
2129
* we kill the thread...
2131
if(myGlobals.capturePackets == FLAG_NTOPSTATE_STOPCAP) {
2132
traceEvent(CONST_TRACE_WARNING, "RRD: STOPCAP, ending rrd thread");
2137
#ifdef CFG_MULTITHREADED
2138
traceEvent(CONST_TRACE_WARNING, "THREADMGMT: rrd thread (%ld) terminated", rrdThread);
2141
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: rrdMainLoop() terminated.");
2148
/* ****************************** */
2150
static int initRRDfunct(void) {
2154
traceEvent(CONST_TRACE_INFO, "RRD: Welcome to the RRD plugin");
2156
#ifdef CFG_MULTITHREADED
2157
createMutex(&rrdMutex);
2160
setPluginStatus(NULL);
2162
if(myGlobals.rrdPath == NULL)
2165
#ifndef CFG_MULTITHREADED
2166
/* This plugin works only with threads */
2167
setPluginStatus("Disabled - requires POSIX thread support.");
2171
if(snprintf(dname, sizeof(dname), "%s", myGlobals.rrdPath) < 0)
2173
if(_mkdir(dname) == -1) {
2174
if(errno != EEXIST) {
2175
traceEvent(CONST_TRACE_ERROR, "RRD: Disabled - unable to create base directory (err %d, %s)",
2177
setPluginStatus("Disabled - unable to create rrd base directory.");
2178
/* Return w/o creating the rrd thread ... disabled */
2182
traceEvent(CONST_TRACE_INFO, "RRD: Created base directory (%s)", dname);
2185
for (i=0; i<sizeof(rrd_subdirs)/sizeof(rrd_subdirs[0]); i++) {
2187
if(snprintf(dname, sizeof(dname), "%s/%s", myGlobals.rrdPath, rrd_subdirs[i]) < 0)
2189
if(_mkdir(dname) == -1) {
2190
if(errno != EEXIST) {
2191
traceEvent(CONST_TRACE_ERROR, "RRD: Disabled - unable to create directory (err %d, %s)", errno, dname);
2192
setPluginStatus("Disabled - unable to create rrd subdirectory.");
2193
/* Return w/o creating the rrd thread ... disabled */
2197
traceEvent(CONST_TRACE_INFO, "RRD: Created directory (%s)", dname);
2201
#ifdef CFG_MULTITHREADED
2202
createThread(&rrdThread, rrdMainLoop, NULL);
2203
traceEvent(CONST_TRACE_INFO, "RRD: Started thread (%ld) for data collection.", rrdThread);
2211
/* ****************************** */
2213
static void termRRDfunct(void) {
2214
#ifdef CFG_MULTITHREADED
2217
/* Hold until rrd is finished or 15s elapsed... */
2218
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Locking mutex (may block for a little while)");
2220
while ((count++ < 5) && (tryLockMutex(&rrdMutex, "Termination") != 0)) {
2223
if(rrdMutex.isLocked) {
2224
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Locked mutex, continuing shutdown");
2226
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Unable to lock mutex, continuing shutdown anyway");
2230
rc = killThread(&rrdThread);
2232
traceEvent(CONST_TRACE_INFO, "RRD: killThread() succeeded");
2234
traceEvent(CONST_TRACE_ERROR, "RRD: killThread() failed, rc %s(%d)", strerror(rc), rc);
2238
if(hostsFilter != NULL) free(hostsFilter);
2239
if(myGlobals.rrdPath != NULL) free(myGlobals.rrdPath);
2241
#ifdef CFG_MULTITHREADED
2242
deleteMutex(&rrdMutex);
2245
traceEvent(CONST_TRACE_INFO, "RRD: Thanks for using the rrdPlugin");
2246
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Done");
2249
initialized = 0; /* Reinit on restart */
2252
/* ****************************** */
2254
/* Plugin entry fctn */
2255
#ifdef MAKE_STATIC_PLUGIN
2256
PluginInfo* rrdPluginEntryFctn(void)
2258
PluginInfo* PluginEntryFctn(void)
2261
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Welcome to %s. (C) 2002-04 by Luca Deri.",
2262
rrdPluginInfo->pluginName);
2264
return(rrdPluginInfo);
2267
/* This must be here so it can access the struct PluginInfo, above */
2268
static void setPluginStatus(char * status) {
2269
if(rrdPluginInfo->pluginStatusMessage != NULL)
2270
free(rrdPluginInfo->pluginStatusMessage);
2271
if(status == NULL) {
2272
rrdPluginInfo->pluginStatusMessage = NULL;
2274
rrdPluginInfo->pluginStatusMessage = strdup(status);