/* * Copyright (C) 2002-07 Luca Deri * * http://www.ntop.org/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Aberrant RRD Behavior (http://cricket.sourceforge.net/aberrant/) patch courtesy of Dominique Karg */ #include "rrdPlugin.h" #ifndef _GETOPT_H #define _GETOPT_H #endif #define REMOTE_SERVER_PORT 2005 static u_char useDaemon = 0; static int sd = -1; static struct sockaddr_in cliAddr, remoteServAddr; #if defined(RRD_DEBUG) && (RRD_DEBUG > 0) #define traceEventRRDebug(level, ...) { if(RRD_DEBUG >= level) \ traceEvent(CONST_TRACE_NOISY, "RRD_DEBUG: " __VA_ARGS__); \ } #define traceEventRRDebugARGV(level) { if(RRD_DEBUG >= level) { \ int _iARGV; \ for(_iARGV=0; _iARGV" "This plugin also produces the graphs of rrd data, available via a
" "link from the various 'Info about host xxxxx' reports.", "2.8", /* version */ "L.Deri", "rrdPlugin", /* http://:/plugins/rrdPlugin */ 1, /* Active by default */ ConfigureOnly, /* use extra pages for the views */ 1, /* Inactive setup */ initRRDfunct, /* TermFunc */ termRRDfunct, /* TermFunc */ NULL, /* PluginFunc */ handleRRDHTTPrequest, NULL, /* no host creation/deletion handle */ NULL, /* no capture */ NULL, /* no status */ rrdExtraPages /* no extra pages */ } }; /* ****************************************************** */ static char **calcpr=NULL; static void calfree (void) { if(calcpr) { long i; for(i=0; calcpr[i]; i++){ if(calcpr[i]) free(calcpr[i]); } if(calcpr) free(calcpr); } } /* ******************************************* */ static char* capitalizeInitial(char *str) { char c = toupper(str[0]); // traceEvent(CONST_TRACE_INFO, "RRD: (%s)", str); str[0] = c; return(str); } /* ******************************************* */ static void fillupArgv(int argc, int maxArgc, char *argv[]) { int i; for(i=argc; i 0) { #ifdef WIN32 Sleep((int)dumpDelay); #else struct timespec sleepAmount; sleepAmount.tv_sec = 0; sleepAmount.tv_nsec = (int)dumpDelay * 1000; nanosleep(&sleepAmount, NULL); #endif } gettimeofday(&lastSleep, NULL); } /* ******************************************* */ static void createMultihostGraph(char *rrdName, HostTraffic *rrdHosts[MAX_NUM_NETWORKS], u_int32_t numRrdHosts, char *startTime, char* endTime) { char buf[512], hosts[512] = { '\0' }; int i; for(i=0; iethAddressString[0] != '\0') ? rrdHosts[i]->ethAddressString : rrdHosts[i]->hostNumIpAddress; if((strlen(hosts) + strlen(host_ip)) < sizeof(hosts)) { if(i > 0) strcat(hosts, ","); strcat(hosts, host_ip); strcat(hosts, "@"); strcat(hosts, rrdHosts[i]->hostResolvedName); } } /* safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "", rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\n", rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts); sendString(buf); */ safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), " \n", rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "" "\n", rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts); sendString(buf); } /* ******************************************* */ static void expandRRDList(char *rrdName, u_int32_t localNetworks[MAX_NUM_NETWORKS][4], /* [0]=network, [1]=mask, [2]=broadcast, [3]=mask_v6 */ u_short numLocalNetworks, char *startTime, char* endTime) { char path[256], rrdName_copy[64], debug=0; u_int32_t numRrdHosts = 0, i; HostTraffic *rrdHosts[MAX_NUM_NETWORKS]; if(debug) traceEvent(CONST_TRACE_WARNING, "RRD: expandRRDList(%s)", rrdName); safe_snprintf(__FILE__, __LINE__, rrdName_copy, sizeof(rrdName_copy), "%s", rrdName); rrdName_copy[strlen(rrdName_copy)-strlen(CONST_RRD_EXTENSION)] = '\0'; for(i=0; iethAddressString[0] != '\0') ? el->ethAddressString : el->hostNumIpAddress, rrdName); for(j=strlen(myGlobals.rrdPath) +strlen("/interfaces/") +strlen(myGlobals.device[myGlobals.actualReportDeviceId].uniqueIfName) +strlen("/hosts/"); j %s [%u]", path, num_network_bits(localNetworks[i][1])); rrdHosts[numRrdHosts++] = el; } } } if(numRrdHosts > 0) createMultihostGraph(rrdName_copy, rrdHosts, numRrdHosts, startTime, endTime); if(debug) traceEvent(CONST_TRACE_WARNING, "RRD: -------------------------"); } /* ******************************************* */ static int cmpStrings(const void *_a, const void *_b) { char **str_a = (char**)_a; char **str_b = (char**)_b; /* traceEvent(CONST_TRACE_WARNING, "RRD: [%s][%s]", *str_a, *str_b); */ return(strcmp(*str_a, *str_b)); } /* ******************************************* */ static void listResource(char *rrdPath, char *rrdTitle, char *cluster, char *startTime, char* endTime) { char path[512], url[512], hasNetFlow, buf[512]; DIR* directoryPointer=NULL; struct dirent* dp; int i, debug = 0; #if 0 int numFailures = 0; #endif time_t now = time(NULL); if(!validHostCommunity(rrdTitle)) { returnHTTPpageBadCommunity(); return; } sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s", myGlobals.rrdPath, rrdPath); revertSlashIfWIN32(path, 0); if(cluster == NULL) safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Info about %s", rrdTitle); else safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Info about cluster %s", cluster); printHTMLheader(buf, NULL, 0); sendString("

\n"); safe_snprintf(__FILE__, __LINE__, url, sizeof(url), "/" CONST_PLUGINS_HEADER "%s?action=list&key=%s&title=%s&end=%u&cluster=%s", rrdPluginInfo->pluginURLname, rrdPath, rrdTitle, (unsigned long)now, cluster ? cluster : ""); sendString("\n"); sendString("

\nPresets: \n" "

\n
\n

\n"); sendString("\n"); if(cluster == NULL) { directoryPointer = opendir(path); if(directoryPointer == NULL) { sendString("
"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Unable to read directory %s", path); traceEvent(CONST_TRACE_INFO, "RRD: %s", buf); printFlagedWarning(buf); sendString("

"); printHTMLtrailer(); return; } hasNetFlow = 0; while((dp = readdir(directoryPointer)) != NULL) { if(strncmp(dp->d_name, "NF_", 3) == 0) { hasNetFlow = 1; break; } } /* while */ closedir(directoryPointer); if(hasNetFlow) { for(i=0; i<=2; i++) { sendString(""); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\n", rrdPluginInfo->pluginURLname, i, rrdPath, startTime, endTime); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\n" "\n", rrdPluginInfo->pluginURLname, i, rrdPath, startTime, endTime); sendString(buf); sendString("\n"); } } directoryPointer = opendir(path); if(directoryPointer == NULL) { safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Unable to read directory %s", path); printFlagedWarning(buf); sendString(""); printHTMLtrailer(); return; } else { // traceEvent(CONST_TRACE_WARNING, "RRD: reading directory %s", path); /* FIX */ } while((dp = readdir(directoryPointer)) != NULL) { char *rsrcName; Counter total; #if 0 float average; #endif int rc, isGauge; if(dp->d_name[0] == '.') continue; else if(strncmp(dp->d_name, "NF_", 3) == 0) continue; else if(strlen(dp->d_name) < strlen(CONST_RRD_EXTENSION)+3) continue; rsrcName = &dp->d_name[strlen(dp->d_name)-strlen(CONST_RRD_EXTENSION)-3]; if(strcmp(rsrcName, "Num"CONST_RRD_EXTENSION) == 0) isGauge = 1; else isGauge = 0; rsrcName = &dp->d_name[strlen(dp->d_name)-strlen(CONST_RRD_EXTENSION)]; if(strcmp(rsrcName, CONST_RRD_EXTENSION)) continue; #if 0 if(sumCounter(rrdPath, dp->d_name, "FAILURES", startTime, endTime, &total, &average) >= 0) numFailures += total; #endif #if DISPLAY_ONLY_IF_THERE_S_DATA rc = sumCounter(rrdPath, dp->d_name, "MAX", startTime, endTime, &total, &average); #else rc = 1, total = 1; #endif if(isGauge || ((rc >= 0) && (total > 0))) { rsrcName = dp->d_name; /* if(strcmp(rsrcName, "pktSent") || strcmp(rsrcName, "pktRcvd")) continue; */ if(strncmp(rsrcName, "IP_", 3) || strncmp(rsrcName, "tcp", 3) || strncmp(rsrcName, "udp", 3) ) { if(!strstr(rsrcName, "Rcvd")) { sendString("\n"); safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "\n", rrdPluginInfo->pluginURLname, rrdPath, rsrcName, rsrcName, startTime, endTime); sendString(path); safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "" "

\n", rrdPluginInfo->pluginURLname, rrdPath, rsrcName, rsrcName, startTime, endTime); sendString(path); sendString("\n"); } } } } /* while */ closedir(directoryPointer); } else { /* Cluster */ char clusterAddresses[256] = { '\0' }, localAddresses[1024] = { '\0' }; u_int32_t localNetworks[MAX_NUM_NETWORKS][4]; /* [0]=network, [1]=mask, [2]=broadcast, [3]=mask_v6 */ u_short numLocalNetworks = 0, found = 0, num_rrds = 0; char *keys[MAX_NUM_RRDS]; int k; snprintf(buf, sizeof(buf), "cluster.%s", cluster); if(fetchPrefsValue(buf, clusterAddresses, sizeof(clusterAddresses)) != -1) { handleAddressLists(clusterAddresses, localNetworks, &numLocalNetworks, localAddresses, sizeof(localAddresses), CONST_HANDLEADDRESSLISTS_CLUSTERS); } for(i=0; iethAddressString[0] != '\0') ? el->ethAddressString : el->hostNumIpAddress); for(j=strlen(path)-strlen((el->ethAddressString[0] != '\0') ? el->ethAddressString : el->hostNumIpAddress); jd_name[0] == '.') /* || (!strstr(dp->d_name, "Sent")) */) continue; else { int duplicated = 0; found = 1; for(k=0; kd_name)) { duplicated = 1; break; } if((!duplicated) && (num_rrds < (MAX_NUM_RRDS-1))) keys[num_rrds++] = strdup(dp->d_name); } } closedir(directoryPointer); } else if(debug) traceEvent(CONST_TRACE_INFO, "RRD: NOT found %s", path); } } qsort(keys, num_rrds, sizeof(char*), cmpStrings); sendString("\n"); for(k=0; k\n"); if(strstr(keys[k], "Rcvd")) { if((k > 0) && strstr(keys[k-1], "Rcvd")) sendString("\n"); sendString(""); else if(strstr(keys[k], "Sent")) sendString("\n"); } sendString("
 
"); } else if(strstr(keys[k], "Sent")) { if((k > 0) && strstr(keys[k-1], "Sent")) sendString("
 "); else sendString(""); } if(0) sendString("ImageLink"); else expandRRDList(keys[k], localNetworks, numLocalNetworks, startTime, endTime); if(strstr(keys[k], "Rcvd")) sendString("
"); if(!found) { sendString(""); printFlagedWarning("No data (yet) for this cluster"); sendString(""); } } sendString("\n"); /* sendString("
NOTE: total and average values are NOT absolute but " "calculated on the specified time interval.\n"); */ printHTMLtrailer(); } /* ******************************************* */ static int endsWith(char* label, char* pattern) { int lenLabel, lenPattern; lenLabel = strlen(label); lenPattern = strlen(pattern); if(lenPattern >= lenLabel) return(0); else return(!strcmp(&label[lenLabel-lenPattern], pattern)); } /* ************************ */ static void sendGraphFile(char* fileName, int doNotUnlink) { FILE *fd; int len; char tmpStr[256]; int bufSize=sizeof(tmpStr)-1, totLen = 0; memset(&tmpStr, 0, sizeof(tmpStr)); if((fd = fopen(fileName, "rb")) != NULL) { for(;;) { len = fread(tmpStr, sizeof(char), bufSize, fd); if(len > 0) { sendStringLen(tmpStr, len); totLen += len; } if(len <= 0) break; } fclose(fd); } else traceEvent(CONST_TRACE_WARNING, "Unable to open file %s - graphic not sent", fileName); if (doNotUnlink == 0) { unlink(fileName); } } /* ******************************* */ static char* sanitizeRrdPath(char *in_path) { #ifdef WIN32 if(in_path[1] == ':') { char *tmpStr; tmpStr = (char*)malloc(strlen(in_path)+2); if(tmpStr) { tmpStr[0] = in_path[0]; tmpStr[1] = '\\'; strcpy(&tmpStr[2], &in_path[1]); strcpy(in_path, tmpStr); free(tmpStr); } } #endif return(in_path); } /* ******************************************* */ static int graphCounter(char *rrdPath, char *rrdName, char *rrdTitle, char *rrdCounter, char *startTime, char* endTime, char *rrdPrefix) { char path[512], *argv[64], buf[384], buf1[384], buf2[384], fname[384], *label, tmpStr[32]; char bufa1[384], bufa2[384], bufa3[384], show_trend = 1; struct stat statbuf; int argc = 0, rc, x, y; double ymin,ymax; #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "graphCounter(%s, %s, %s, %s, %s, %s...)", rrdPath, rrdName, rrdTitle, rrdCounter, startTime, endTime); #endif memset(&buf, 0, sizeof(buf)); memset(&buf1, 0, sizeof(buf1)); memset(&buf2, 0, sizeof(buf2)); memset(&bufa1, 0, sizeof(bufa1)); memset(&bufa2, 0, sizeof(bufa2)); memset(&bufa3, 0, sizeof(bufa3)); if(strstr(rrdName, "AS")) safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s/AS/%s.rrd", myGlobals.rrdPath, rrdPath, rrdName); else { if(!strcmp(rrdName, "throughput")) { #ifdef WIN32 safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s%s.rrd", myGlobals.spoolPath, driveSerial, rrdPath, rrdName); #else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.spoolPath, rrdPath, rrdName); #endif } else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.rrdPath, rrdPath, rrdName); } /* startTime[4] skips the 'now-' */ safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s-%s%s%s", myGlobals.rrdPath, rrd_subdirs[0], startTime, rrdPrefix, rrdName, CHART_FORMAT); revertSlashIfWIN32(path, 0); revertSlashIfWIN32(fname, 0); if(endsWith(rrdName, "Bytes")) label = "Bytes/s"; else if(endsWith(rrdName, "Pkts")) label = "Pkt/s"; else label = capitalizeInitial(rrdName); if((!strcmp(endTime, "now")) && (!strcmp(startTime, "now-600s"))) show_trend = 0; rrdGraphicRequests++; if(stat(path, &statbuf) == 0) { char metric_name[32]; if(isdigit(startTime[0]) && isdigit(endTime[0])) { unsigned long _startTime, _endTime; _startTime = atol(startTime); _endTime = atol(endTime); if(_startTime >= _endTime) { char *tmp = startTime; startTime = endTime; endTime = tmp; } } argv[argc++] = "rrd_graph"; argv[argc++] = fname; argv[argc++] = "--lazy"; argv[argc++] = "--imgformat"; argv[argc++] = "PNG"; argv[argc++] = "--vertical-label"; argv[argc++] = label; if((rrdTitle != NULL) && (rrdTitle[0] != '\0')) { argv[argc++] = "--title"; argv[argc++] = rrdTitle; } argv[argc++] = "--start"; argv[argc++] = startTime; argv[argc++] = "--end"; argv[argc++] = endTime; argv[argc++] = "--slope-mode"; /* ********************* */ argv[argc++] = "--rigid"; argv[argc++] = "--base"; argv[argc++] = "1024"; argv[argc++] = "--height"; argv[argc++] = "120"; argv[argc++] = "--width"; argv[argc++] = "500"; argv[argc++] = "--alt-autoscale-max"; argv[argc++] = "--lower-limit"; argv[argc++] = "0"; /* ********************* */ #ifdef CONST_RRD_DEFAULT_FONT_NAME argv[argc++] = "--font"; #ifdef CONST_RRD_DEFAULT_FONT_PATH argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \ CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME; #else argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME; #endif #endif revertDoubleColumnIfWIN32(path); sanitizeRrdPath(path); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "DEF:ctr=%s:counter:AVERAGE", path); argv[argc++] = buf; safe_snprintf(__FILE__, __LINE__, buf1, sizeof(buf1), "AREA:ctr#00a000:%s", spacer(capitalizeInitial(rrdCounter), tmpStr, sizeof(tmpStr), metric_name, sizeof(metric_name))); argv[argc++] = buf1; if(show_trend) argv[argc++] = "CDEF:smoothed=ctr,1800,TREND"; argv[argc++] = "GPRINT:ctr:MIN:Min\\: %3.1lf%s"; argv[argc++] = "GPRINT:ctr:MAX:Max\\: %3.1lf%s"; argv[argc++] = "GPRINT:ctr:AVERAGE:Avg\\: %3.1lf%s"; argv[argc++] = "GPRINT:ctr:LAST:Last\\: %3.1lf%s\\n"; safe_snprintf(__FILE__, __LINE__, bufa1, sizeof(bufa1), "DEF:pred=%s:counter:HWPREDICT", path); argv[argc++] = bufa1; safe_snprintf(__FILE__, __LINE__, bufa2, sizeof(bufa2), "DEF:dev=%s:counter:DEVPREDICT", path); argv[argc++] = bufa2; safe_snprintf(__FILE__, __LINE__, bufa3, sizeof(bufa3), "DEF:fail=%s:counter:FAILURES", path); argv[argc++] = bufa3; if(enableAberrant) { argv[argc++] = "TICK:fail#ffffa0:1.0:Anomalia"; argv[argc++] = "CDEF:upper=pred,dev,2,*,+"; argv[argc++] = "CDEF:lower=pred,dev,2,*,-"; argv[argc++] = "LINE1:upper#ff0000:Upper"; argv[argc++] = "LINE2:lower#a0ffff:Lower"; } if(show_trend) argv[argc++] = "LINE1:smoothed#0000FF:Trend (30 min)"; accessMutex(&rrdMutex, "rrd_graph"); optind=0; /* reset gnu getopt */ opterr=0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); addRrdDelay(); rc = rrd_graph(argc, argv, &calcpr, &x, &y, NULL, &ymin, &ymax); calfree(); if(rc == 0) { sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1); sendGraphFile(fname, 0); unlink(fname); } else { traceEventRRDebugARGV(0); if(++graphErrCount < 50) { traceEvent(CONST_TRACE_ERROR, "RRD: rrd_graph() call failed, rc %d, %s", rc, rrd_get_error() ? rrd_get_error() : ""); traceEvent(CONST_TRACE_INFO, "RRD: Failing file in graphCounter() is %s", path); } sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Graph", NULL, 0); safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "Error while building graph of the requested file. %s", rrd_get_error() ? rrd_get_error() : ""); printFlagedWarning(path); rrd_clear_error(); } releaseMutex(&rrdMutex); } else { sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Graph", NULL, 0); printFlagedWarning("Error while building graph of the requested file " "(unknown RRD file)"); rc = -1; } return(rc); } /* ******************************************* */ #define MAX_NUM_ENTRIES 32 #define MAX_BUF_LEN 128 #undef option_timespan #define option_timespan(theStartTime, theLabel, selected) \ safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), \ "\n", \ "rrdPlugin", rrdInterface, graphId, (unsigned int)theStartTime, (unsigned int)the_time, \ _rrdName, (selected == 1) ? "selected" : "", theLabel); sendString(strbuf); /* ****************************** */ static void netflowSummary(char *rrdPath, int graphId, char *startTime, char* endTime, char *rrdPrefix, char *mode) { char path[512], *argv[3*MAX_NUM_ENTRIES], buf[MAX_NUM_ENTRIES][MAX_BUF_LEN]; char buf1[MAX_NUM_ENTRIES][MAX_BUF_LEN], tmpStr[32], buf2[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf3[MAX_NUM_ENTRIES][MAX_BUF_LEN]; char fname[384], *label, _rrdName[256]; char **rrds = NULL; int argc = 0, rc, x, y, i, entryId=0; double ymin, ymax; path[0] = '\0'; switch(graphId) { case 0: rrds = (char**)rrd_summary_new_flows; label = "Flows"; break; case 1: rrds = (char**)rrd_summary_new_nf_flows; label = "Flows"; break; case 2: rrds = (char**)rrd_summary_new_nf_flows_size; label = "Bytes"; break; } /* startTime[4] skips the 'now-' */ safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s-%s%d%s", myGlobals.rrdPath, rrd_subdirs[0], startTime, rrdPrefix, graphId, CHART_FORMAT); safe_snprintf(__FILE__, __LINE__, _rrdName, sizeof(_rrdName), "%s", rrdPath); if(!strcmp(mode, "zoom")) { char strbuf[LEN_GENERAL_WORK_BUFFER]; time_t the_time = time(NULL); char *rrdInterface = rrdPath; struct tm *the_tm; sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0); sendString("

\n"); /* *************************************** */ /* Graph time and zoom: code courtesy of the Cacti (http://www.cacti.net) project. */ sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n

\n

\n" "\n
\n" "Presets: \n"); safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), "\n" "\n" "\n" "\n" "\n" "\n" "\n", graphId, _rrdName, rrdInterface, startTime, endTime); sendString(strbuf); sendString(" From:\n\n\n"); sendString(" To:\n\n\n" "\n\n
\n

\n"); /* *************************************** */ sendString("\n" "
\n"); sendString("
\n"); /* NOTE: If the graph size changes, please update the zoom.js file (search for L.Deri) */ safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), "\"graph
\n", rrdPluginInfo->pluginURLname, graphId, rrdInterface, _rrdName, startTime, endTime); sendString(strbuf); sendString("\n\n"); sendString("\n"); printHTMLtrailer(); return; } revertSlashIfWIN32(fname, 0); if(rrds == NULL) { sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Graph Summary", NULL, 0); printFlagedWarning("Error while building graph of the requested file " "(unknown RRD files)"); return; } rrdGraphicRequests++; if(isdigit(startTime[0]) && isdigit(endTime[0])) { unsigned long _startTime, _endTime; _startTime = atol(startTime); _endTime = atol(endTime); if(_startTime >= _endTime) { char *tmp = startTime; startTime = endTime; endTime = tmp; } } argv[argc++] = "rrd_graph"; argv[argc++] = fname; argv[argc++] = "--lazy"; argv[argc++] = "--imgformat"; argv[argc++] = "PNG"; argv[argc++] = "--vertical-label"; argv[argc++] = label; argv[argc++] = "--start"; argv[argc++] = startTime; argv[argc++] = "--end"; argv[argc++] = endTime; argv[argc++] = "--slope-mode"; #ifdef CONST_RRD_DEFAULT_FONT_NAME argv[argc++] = "--font"; #ifdef CONST_RRD_DEFAULT_FONT_PATH argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \ CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME; #else argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME; #endif #endif revertDoubleColumnIfWIN32(path); for(i=0, entryId=0; rrds[i] != NULL; i++) { struct stat statbuf; if(!strcmp(rrds[i], "throughput")) { #ifdef WIN32 safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s%s.rrd", myGlobals.spoolPath, driveSerial, rrdPath, rrds[i]); #else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.spoolPath, rrdPath, rrds[i]); #endif } else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.rrdPath, rrdPath, rrds[i]); revertSlashIfWIN32(path, 0); if(stat(path, &statbuf) == 0) { char metric_name[32]; safe_snprintf(__FILE__, __LINE__, buf[entryId], MAX_BUF_LEN, "DEF:ctr%d=%s:counter:AVERAGE", entryId, path); argv[argc++] = buf[entryId]; safe_snprintf(__FILE__, __LINE__, buf1[entryId], MAX_BUF_LEN, "%s:ctr%d%s:%s", entryId == 0 ? "AREA" : "STACK", entryId, rrd_colors[entryId], spacer(&rrds[i][3], tmpStr, sizeof(tmpStr), metric_name, sizeof(metric_name))); argv[argc++] = buf1[entryId]; safe_snprintf(__FILE__, __LINE__, buf2[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":AVERAGE:Avg\\: %3.1lf%s\\t"); argv[argc++] = buf2[entryId]; safe_snprintf(__FILE__, __LINE__, buf3[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":LAST:Last\\: %3.1lf%s\\n"); argv[argc++] = buf3[entryId]; entryId++; } else { // traceEvent(CONST_TRACE_WARNING, "RRD: Unable to find file %s", path); } if(entryId >= MAX_NUM_ENTRIES) break; if(entryId >= CONST_NUM_BAR_COLORS) { if(colorWarn == 0) { traceEvent(CONST_TRACE_WARNING, "RRD: Number of defined bar colors less than max entries. Some graph(s) truncated"); colorWarn = 1; } break; } } accessMutex(&rrdMutex, "rrd_graph"); optind=0; /* reset gnu getopt */ opterr=0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); addRrdDelay(); rc = rrd_graph(argc, argv, &calcpr, &x, &y, NULL, &ymin, &ymax); calfree(); if(rc == 0) { sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1); sendGraphFile(fname, 0); unlink(fname); } else { traceEventRRDebugARGV(3); if(++graphErrCount < 50) { traceEvent(CONST_TRACE_ERROR, "RRD: rrd_graph() call failed, rc %d, %s", rc, rrd_get_error() ? rrd_get_error() : ""); traceEvent(CONST_TRACE_INFO, "RRD: Failing file in netflowSummary() is %s", path); } sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Graph Summary", NULL, 0); safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "Error while building graph of the requested file. %s", rrd_get_error() ? rrd_get_error() : ""); printFlagedWarning(path); rrd_clear_error(); } releaseMutex(&rrdMutex); } /* ******************************************* */ #define MAX_NUM_ENTRIES 32 #define MAX_BUF_LEN 128 #undef option_timespan #define option_timespan(theStartTime, theLabel, selected) \ safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), \ "\n", \ "rrdPlugin", rrdInterface, graphId, (unsigned int)theStartTime, (unsigned int)the_time, \ _rrdName, (selected == 1) ? "selected" : "", theLabel); sendString(strbuf); static void interfaceSummary(char *rrdPath, int graphId, char *startTime, char* endTime, char *rrdPrefix, char *mode) { char path[512], *argv[3*MAX_NUM_ENTRIES], buf[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf0[MAX_NUM_ENTRIES][MAX_BUF_LEN]; char buf1[MAX_NUM_ENTRIES][MAX_BUF_LEN], tmpStr[32], metric_name[32], buf2[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf3[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf4[MAX_NUM_ENTRIES][MAX_BUF_LEN]; char fname[384], *label, title[64], _rrdName[256]; char **rrds = NULL; int argc = 0, rc, x, y, i, entryId=0; double ymin, ymax; path[0] = '\0'; safe_snprintf(__FILE__, __LINE__, _rrdName, sizeof(_rrdName), "%s", rrdPath); switch(graphId) { case 0: rrds = (char**)rrd_summary_nf_if_octets; label = "Bit/s"; break; default: rrds = (char**)rrd_summary_nf_if_pkts; label = "Pkt/s"; break; } traceEvent(CONST_TRACE_WARNING, "-- 0 --> (%s)", "Hello"); if(!strcmp(mode, "zoom")) { char strbuf[LEN_GENERAL_WORK_BUFFER]; time_t the_time = time(NULL); char *rrdInterface = rrdPath; struct tm *the_tm; sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0); sendString("
\n"); /* *************************************** */ /* Graph time and zoom: code courtesy of the Cacti (http://www.cacti.net) project. */ sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n

\n

\n\n
\nPresets: \n"); safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), "\n" "\n" "\n" "\n" "\n" "\n" "\n", graphId, _rrdName, rrdInterface, startTime, endTime); sendString(strbuf); sendString(" From:\n\n\n"); sendString(" To:\n\n\n" "\n\n
\n

\n"); /* *************************************** */ sendString("\n" "
\n"); sendString("
\n"); /* NOTE: If the graph size changes, please update the zoom.js file (search for L.Deri) */ safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), "\"graph
\n", rrdPluginInfo->pluginURLname, graphId, rrdInterface, _rrdName, startTime, endTime); sendString(strbuf); sendString("\n\n"); sendString("\n"); printHTMLtrailer(); return; } /* startTime[4] skips the 'now-' */ safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s/%s-%s%d%s", myGlobals.rrdPath, rrd_subdirs[2], rrdPath, startTime, rrdPrefix, graphId, CHART_FORMAT); revertSlashIfWIN32(fname, 0); if(rrds == NULL) { sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Graph Summary", NULL, 0); printFlagedWarning("Error while building graph of the requested file " "(unknown RRD files)"); return; } for(i=strlen(rrdPath)-1; i>0; i--) if(rrdPath[i] == '/') break; if(strstr(rrdPath, "/AS/")) safe_snprintf(__FILE__, __LINE__, title, sizeof(title), "AS %s", &rrdPath[i+1]); else safe_snprintf(__FILE__, __LINE__, title, sizeof(title), "NetFlow Interface %s", &rrdPath[i+1]); rrdGraphicRequests++; if(isdigit(startTime[0]) && isdigit(endTime[0])) { unsigned long _startTime, _endTime; _startTime = atol(startTime); _endTime = atol(endTime); if(_startTime >= _endTime) { char *tmp = startTime; startTime = endTime; endTime = tmp; } } argv[argc++] = "rrd_graph"; argv[argc++] = fname; argv[argc++] = "--lazy"; argv[argc++] = "--imgformat"; argv[argc++] = "PNG"; argv[argc++] = "--vertical-label"; argv[argc++] = label; argv[argc++] = "--title"; argv[argc++] = title; argv[argc++] = "--start"; argv[argc++] = startTime; argv[argc++] = "--end"; argv[argc++] = endTime; argv[argc++] = "--slope-mode"; argv[argc++] = "--width"; argv[argc++] = "500"; argv[argc++] = "--height"; argv[argc++] = "120"; argv[argc++] = "--alt-autoscale-max"; argv[argc++] = "--lower-limit"; argv[argc++] = "0"; #ifdef CONST_RRD_DEFAULT_FONT_NAME argv[argc++] = "--font"; #ifdef CONST_RRD_DEFAULT_FONT_PATH argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \ CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME; #else argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME; #endif #endif for(i=0, entryId=0; rrds[i] != NULL; i++) { struct stat statbuf; if(!strcmp(rrds[i], "throughput")) { #ifdef WIN32 safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s/%s/%s.rrd", myGlobals.spoolPath, driveSerial, rrd_subdirs[2], rrdPath, rrds[i]); #else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s/%s/%s.rrd", myGlobals.spoolPath, rrd_subdirs[2], rrdPath, rrds[i]); #endif } else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s/%s/%s.rrd", myGlobals.rrdPath, rrd_subdirs[2], rrdPath, rrds[i]); revertSlashIfWIN32(path, 0); if(stat(path, &statbuf) == 0) { safe_snprintf(__FILE__, __LINE__, buf[entryId], MAX_BUF_LEN, "DEF:bctr%d=%s:counter:AVERAGE", entryId, path); argv[argc++] = buf[entryId]; safe_snprintf(__FILE__, __LINE__, buf0[entryId], MAX_BUF_LEN, "CDEF:ctr%d=bctr%d,8,*", entryId, entryId); argv[argc++] = buf0[entryId]; safe_snprintf(__FILE__, __LINE__, buf1[entryId], MAX_BUF_LEN, "%s:ctr%d%s:%s", entryId == 0 ? "AREA" : "STACK", entryId, rrd_colors[entryId], spacer(&rrds[i][2], tmpStr, sizeof(tmpStr), metric_name, sizeof(metric_name))); argv[argc++] = buf1[entryId]; safe_snprintf(__FILE__, __LINE__, buf2[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":LAST:Last\\: %8.2lf %s"); argv[argc++] = buf2[entryId]; safe_snprintf(__FILE__, __LINE__, buf3[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":AVERAGE:Avg\\: %8.2lf %s"); argv[argc++] = buf3[entryId]; safe_snprintf(__FILE__, __LINE__, buf4[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":MAX:Max\\: %8.2lf %s\\n"); argv[argc++] = buf4[entryId]; entryId++; } if(entryId >= MAX_NUM_ENTRIES) break; if(entryId >= CONST_NUM_BAR_COLORS) { if(colorWarn == 0) { traceEvent(CONST_TRACE_WARNING, "RRD: Number of defined bar colors less than max entries. Some graph(s) truncated"); colorWarn = 1; } break; } } /* traceEventRRDebugARGV(0); */ accessMutex(&rrdMutex, "rrd_graph"); optind=0; /* reset gnu getopt */ opterr=0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); addRrdDelay(); rc = rrd_graph(argc, argv, &calcpr, &x, &y, NULL, &ymin, &ymax); traceEventRRDebugARGV(3); // FIX calfree(); if(rc == 0) { sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1); sendGraphFile(fname, 0); unlink(fname); } else { traceEventRRDebugARGV(3); if(++graphErrCount < 50) { traceEvent(CONST_TRACE_ERROR, "RRD: rrd_graph() call failed, rc %d, %s", rc, rrd_get_error() ? rrd_get_error() : ""); traceEvent(CONST_TRACE_INFO, "RRD: Failing file in netflowSummary() is %s", path); } sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Graph Summary", NULL, 0); safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "Error while building graph of the requested file. %s", rrd_get_error() ? rrd_get_error() : ""); printFlagedWarning(path); rrd_clear_error(); } releaseMutex(&rrdMutex); } /* ******************************* */ static char* spacer(char* str, char *tmpStr, int tmpStrLen, char *metric_name, int metric_name_len) { int len = strlen(str), i; char *token, *token_name, buf[32], debug = 0, *found, *key; if((strlen(str) > 3) && (!strncmp(str, "IP_", 3))) str += 3; if(debug) traceEvent(CONST_TRACE_WARNING, "-- 0 --> (%s)", str); memset(tmpStr, 0, tmpStrLen); if((token = strstr(str, "Bytes")) != NULL) token_name = "Bytes"; else if((token = strstr(str, "Octets")) != NULL) token_name = "Octets"; else if((token = strstr(str, "Pkts")) != NULL) token_name = "Pkts"; else if((token = strstr(str, "Flows")) != NULL) token_name = "Flows"; else if((token = strstr(str, "AS")) != NULL) token_name = "AS"; else if((token = strstr(str, "Num")) != NULL) token_name = "Num"; else token = NULL, token_name = NULL; if(debug) traceEvent(CONST_TRACE_WARNING, "-- 000 --> (%s)", str); if(token) { char add_trailer; char save_char = token[0]; if(strlen(token_name) == strlen(token)) add_trailer = 0; else add_trailer = 1; if(debug) traceEvent(CONST_TRACE_WARNING, "-- 11 --> (%s)(%s) [add_trailer=%d]", token, token_name, add_trailer); if(add_trailer) { if(debug) traceEvent(CONST_TRACE_WARNING, "-- 1 --> (%s)", str); token[0] = '\0'; safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s%s", str, &token[strlen(token_name)]); token[0] = save_char; } else { if(debug) traceEvent(CONST_TRACE_WARNING, "-- 2 --> (%s)", str); len = strlen(str)-strlen(token); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s", str); buf[len] = '\0'; } } else { if(debug) traceEvent(CONST_TRACE_WARNING, "-- 3 --> (%s)", str); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s", str); } if((found = strstr(buf, "Sent")) != NULL) key = "Sent"; else if((found = strstr(buf, "Rcvd")) != NULL) key = "Rcvd"; else if((found = strstr(buf, "Peers")) != NULL) key = "Peers"; else found = NULL; if(found) { found[0] = ' '; for(i=1; i<(1+strlen(key)); i++) found[i] = key[i-1]; found[i] = '\0'; } len = strlen(buf); if(len > 15) len = 15; snprintf(tmpStr, len+1, "%s", buf); for(i=len; i<15; i++) tmpStr[i] = ' '; tmpStr[16] = '\0'; if(debug) traceEvent(CONST_TRACE_WARNING, "-- 4 --> (%s)", tmpStr); if(token_name) safe_snprintf(__FILE__, __LINE__, metric_name, metric_name_len, "%s", token_name); else memset(metric_name, 0, metric_name_len); return(tmpStr); } /* ******************************* */ static char* formatTitle(char *str, char *buf, u_short buf_len) { int len, shift = 0; if(buf_len <= (strlen(str) + 10)) return(str); /* No much space */ if(!strncmp(str, "IP_", 3)) shift = 3; safe_snprintf(__FILE__, __LINE__, buf, buf_len, "%s", &str[shift]); len = strlen(buf); if(!strcmp(&buf[len-7], "LocSent")) { buf[len-7] = '\0'; strcat(buf, " Sent Locally"); } else if(!strcmp(&buf[len-9], "BytesSent")) { buf[len-9] = '\0'; strcat(buf, " Sent (Bytes)"); } else if(!strcmp(&buf[len-7], "RemSent")) { buf[len-7] = '\0'; strcat(buf, " Sent to Remote Hosts"); } else if(!strcmp(&buf[len-4], "Sent")) { buf[len-4] = '\0'; strcat(buf, " Sent"); } else if(!strcmp(&buf[len-9], "BytesRcvd")) { buf[len-9] = '\0'; strcat(buf, " Received (Bytes)"); } else if(!strcmp(&buf[len-7], "LocRcvd")) { buf[len-7] = '\0'; strcat(buf, " Rcvd From Local Hosts"); } else if(!strcmp(&buf[len-11], "FromRemRcvd")) { buf[len-11] = '\0'; strcat(buf, " Rcvd From Remote Hosts"); } else if(!strcmp(&buf[len-4], "Rcvd")) { buf[len-4] = '\0'; strcat(buf, " Received"); } return(buf); } /* ****************************** */ #undef option_timespan #define option_timespan(theStartTime, theLabel, selected) \ safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), \ "\n", \ "rrdPlugin", rrdInterface, graphId, (unsigned int)theStartTime, (unsigned int)the_time, \ _rrdName, (selected == 1) ? "selected" : "", theLabel); sendString(buf); /* ******************************* */ #define MAX_NUM_RRD_ENTRIES 3 #define MAX_NUM_RRD_HOSTS 32 static void graphSummary(char *rrdPath, char *rrdName, int graphId, char *startTime, char* endTime, char *rrdPrefix, char *mode) { char path[512], *argv[6*MAX_NUM_ENTRIES], tmpStr[32], fname[384], *label, rrdPath_copy[512]; char buf0[MAX_NUM_ENTRIES][2*MAX_BUF_LEN], buf1[MAX_NUM_ENTRIES][2*MAX_BUF_LEN]; char buf3[MAX_NUM_ENTRIES][2*MAX_BUF_LEN]; char buf4[MAX_NUM_ENTRIES][2*MAX_BUF_LEN], buf5[MAX_NUM_ENTRIES][2*MAX_BUF_LEN], _rrdName[256]; char **rrds = NULL, ipRRDs[MAX_NUM_ENTRIES][MAX_BUF_LEN], *myRRDs[MAX_NUM_ENTRIES]; int argc = 0, rc, x, y, i, entryId=0, num_rrd_hosts_path = 0, j; DIR* directoryPointer; char *rrd_custom[MAX_NUM_RRD_ENTRIES], *rrd_hosts_path[MAX_NUM_RRD_HOSTS], *rrd_hosts[MAX_NUM_RRD_HOSTS], file_a[32], file_b[32], title_buf[48]; double ymin,ymax; i = strlen(rrdPath); if((i > 1) && (rrdPath[i-1] == '/')) rrdPath[i-1] = '\0'; path[0] = '\0', label = ""; safe_snprintf(__FILE__, __LINE__, _rrdName, sizeof(_rrdName), "%s", rrdName); switch(graphId) { case 0: rrds = (char**)rrd_summary_packets; label = "Pkt/s"; break; case 1: rrds = (char**)rrd_summary_packet_sizes; label = "Pkt/s"; break; case 2: rrds = (char**)rrd_summary_proto_bytes; label = "Bytes/s"; break; case 3: rrds = (char**)rrd_summary_ipproto_bytes; label = "Bytes/s"; break; case 4: safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s", myGlobals.rrdPath, rrdPath); revertSlashIfWIN32(path, 0); directoryPointer = opendir(path); if(directoryPointer == NULL) rrds = NULL; else { struct dirent* dp; i = 0; while((dp = readdir(directoryPointer)) != NULL) { int len = strlen(dp->d_name); if(dp->d_name[0] == '.') continue; else if(len < 7 /* IP_ + .rrd */ ) continue; else if(strncmp(dp->d_name, "IP_", 3)) continue; else if(strstr(dp->d_name, "Flows")) continue; len -= 4; if(len > MAX_BUF_LEN) len = MAX_BUF_LEN-1; dp->d_name[len] = '\0'; safe_snprintf(__FILE__, __LINE__, ipRRDs[i], MAX_BUF_LEN, "%s", dp->d_name); myRRDs[i] = ipRRDs[i]; i++; if(i >= MAX_NUM_ENTRIES) break; } myRRDs[i] = NULL; rrds = (char**)myRRDs; closedir(directoryPointer); } label = "Bytes/s"; break; case 5: rrds = (char**)rrd_summary_local_remote_ip_bytes; label = "Bytes/s"; break; case 6: rrds = (char**)rrd_summary_host_sentRcvd_packets; label = "Pkt/s"; break; case 7: rrds = (char**)rrd_summary_host_sentRcvd_bytes; label = "Bytes/s"; break; case 98: { char *host, *strTokPos; rrd_custom[0] = rrdName; rrd_custom[1] = NULL; rrds = (char**)rrd_custom; safe_snprintf(__FILE__, __LINE__, rrdPath_copy, sizeof(rrdPath_copy), "%s", rrdPath); host = strtok_r(rrdPath_copy, ",", &strTokPos); if(host) { char tmpPath[64]; while(host != NULL) { char *strTokPosHost, *the_host, *the_num_host; if(num_rrd_hosts_path == MAX_NUM_RRD_HOSTS) break; the_host = strtok_r(host, "@", &strTokPosHost); the_num_host = strtok_r(NULL, "@", &strTokPosHost); if((the_num_host == NULL) || (the_num_host[0] == '\0')) the_num_host = "no_name"; rrd_hosts[num_rrd_hosts_path] = strdup(the_num_host); for(y=0; y */ { char *sent = strstr(rrdName, "Sent"); char *rcvd = strstr(rrdName, "Rcvd"); char *pkts = strstr(rrdName, "Pkts"); if(sent || rcvd) { if(sent) sent[0] = '\0'; else rcvd[0] = '\0'; snprintf(file_a, sizeof(file_a), "%sSent", rrdName); snprintf(file_b, sizeof(file_b), "%sRcvd", rrdName); rrd_custom[0] = file_a; rrd_custom[1] = file_b; rrd_custom[2] = NULL; rrds = (char**)rrd_custom; /* traceEvent(CONST_TRACE_WARNING, "RRD: [%s][%s]", file_a, file_b); */ } else { snprintf(file_a, sizeof(file_a), "%s", rrdName); file_a[strlen(file_a)-strlen(CONST_RRD_EXTENSION)] = '\0'; rrd_custom[0] = file_a; rrd_custom[1] = NULL; rrds = (char**)rrd_custom; /* traceEvent(CONST_TRACE_WARNING, "RRD: Not found [%s]", rrdName); */ } if(pkts || strstr(rrdName, "pkt")) label = "Pkt/s"; else if(strstr(rrdName, "Peers")) label = "Contacted Peers"; else if(strstr(rrdName, "knownHosts")) label = "Hosts"; else label = "Bytes/s"; } break; } if(!strcmp(mode, "zoom")) { char buf[LEN_GENERAL_WORK_BUFFER]; time_t the_time = time(NULL); char *rrdInterface = rrdPath; struct tm *the_tm; sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0); sendString("
\n"); /* *************************************** */ /* Graph time and zoom: code courtesy of the Cacti (http://www.cacti.net) project. */ sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n

\n

\n\n
\nPresets: \n"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\n" "\n" "\n" "\n" "\n" "\n" "\n", rrdInterface, graphId, _rrdName, startTime, endTime); sendString(buf); sendString(" From:\n\n\n"); sendString(" To:\n\n\n" "\n\n
\n

\n"); /* *************************************** */ sendString("\n" "
\n"); sendString("
\n"); /* NOTE: If the graph size changes, please update the zoom.js file (search for L.Deri) */ safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\"graph
\n", rrdPluginInfo->pluginURLname, graphId, rrdInterface, _rrdName, startTime, endTime); sendString(buf); sendString("\n\n"); sendString("\n"); printHTMLtrailer(); return; } /* startTime[4] skips the 'now-' */ safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s-%s%d%s", myGlobals.rrdPath, rrd_subdirs[0], startTime, rrdPrefix, graphId, CHART_FORMAT); revertSlashIfWIN32(fname, 0); if(rrds == NULL) { sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Graph Summary", NULL, 0); printFlagedWarning("Error while building graph of the requested file " "(unknown RRD files)"); return; } if(isdigit(startTime[0]) && isdigit(endTime[0])) { unsigned long _startTime, _endTime; _startTime = atol(startTime); _endTime = atol(endTime); if(_startTime >= _endTime) { char *tmp = startTime; startTime = endTime; endTime = tmp; } } rrdGraphicRequests++; argv[argc++] = "rrd_graph"; argv[argc++] = fname; argv[argc++] = "--lazy"; argv[argc++] = "--imgformat"; argv[argc++] = "PNG"; argv[argc++] = "--vertical-label"; argv[argc++] = label; argv[argc++] = "--start"; argv[argc++] = startTime; argv[argc++] = "--end"; argv[argc++] = endTime; argv[argc++] = "--slope-mode"; if(graphId == 98) { argv[argc++] = "--title"; argv[argc++] = formatTitle(rrdName, title_buf, sizeof(title_buf)); } #ifdef CONST_RRD_DEFAULT_FONT_NAME argv[argc++] = "--font"; #ifdef CONST_RRD_DEFAULT_FONT_PATH argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \ CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME; #else argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME; #endif #endif revertDoubleColumnIfWIN32(path); if(graphId != 98) { rrd_hosts_path[num_rrd_hosts_path++] = strdup(rrdPath); } for(j=0, entryId=0; j (%s) [%d/%d]", path, j, num_rrd_hosts_path); */ if(stat(path, &statbuf) == 0) { char metric_name[32]; safe_snprintf(__FILE__, __LINE__, buf0[entryId], 2*MAX_BUF_LEN, "DEF:ctr%d=%s:counter:AVERAGE", entryId, sanitizeRrdPath(path)); argv[argc++] = buf0[entryId]; safe_snprintf(__FILE__, __LINE__, buf1[entryId], 2*MAX_BUF_LEN, "%s:ctr%d%s:%s", entryId == 0 ? "AREA" : "STACK", entryId, rrd_colors[entryId], spacer((graphId == 98) ? rrd_hosts[j] : rrds[i], tmpStr, sizeof(tmpStr), metric_name, sizeof(metric_name))); argv[argc++] = buf1[entryId]; /* safe_snprintf(__FILE__, __LINE__, buf2[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":MIN:Min\\: %3.1lf%s"); argv[argc++] = buf2[entryId]; */ safe_snprintf(__FILE__, __LINE__, buf3[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":MAX:Max\\: %3.1lf%s\\t"); argv[argc++] = buf3[entryId]; safe_snprintf(__FILE__, __LINE__, buf4[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":AVERAGE:Avg\\: %3.1lf%s\\t"); argv[argc++] = buf4[entryId]; safe_snprintf(__FILE__, __LINE__, buf5[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":LAST:Last\\: %3.1lf%s\\n"); argv[argc++] = buf5[entryId]; entryId++; } if(entryId >= MAX_NUM_ENTRIES) break; if(entryId >= CONST_NUM_BAR_COLORS) { if(colorWarn == 0) { traceEvent(CONST_TRACE_ERROR, "RRD: Number of defined bar colors less than max entries. Graphs may be truncated"); colorWarn = 1; } break; } } } accessMutex(&rrdMutex, "rrd_graph"); optind = 0; /* reset gnu getopt */ opterr = 0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); addRrdDelay(); if(0) { for(j=0; jError while building graph of the requested file. %s", rrd_get_error() ? rrd_get_error() : ""); printFlagedWarning(path); rrd_clear_error(); } releaseMutex(&rrdMutex); } /* ******************************* */ static time_t checkLast(char *rrd) { time_t lastTime; char *argv[32]; int argc = 0; argc = 0; argv[argc++] = "rrd_last"; argv[argc++] = rrd; accessMutex(&rrdMutex, "rrd_last"); optind=0; /* reset gnu getopt */ opterr=0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); addRrdDelay(); lastTime = rrd_last(argc, argv); releaseMutex(&rrdMutex); return(lastTime); } /* ******************************* */ static void initUdp() { struct hostent *h; if(!useDaemon) return; /* bind any port */ cliAddr.sin_family = AF_INET; cliAddr.sin_addr.s_addr = htonl(INADDR_ANY); cliAddr.sin_port = htons(0); /* get server IP address (no check if input is IP address or DNS name */ h = gethostbyname("127.0.0.1"); if(h == NULL) { traceEvent(CONST_TRACE_WARNING, "RRD: unknown RRD server host\n"); } remoteServAddr.sin_family = h->h_addrtype; memcpy((char *) &remoteServAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length); remoteServAddr.sin_port = htons(REMOTE_SERVER_PORT); /* socket creation */ sd = socket(AF_INET, SOCK_DGRAM, 0); if(sd < 0) { traceEvent(CONST_TRACE_WARNING, "RRD: cannot create RRD socket"); useDaemon = 0; } } /* ******************************* */ static void updateUdpParams() { char buf[512]; safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "CFG %d\t%d\t%d\t%d\t%d\t%d", dumpInterval, dumpShortInterval, dumpHours, dumpDays, dumpMonths, dumpDelay); sendto(sd, buf, strlen(buf), 0, (struct sockaddr *)&remoteServAddr, sizeof(remoteServAddr)); } /* ******************************* */ static void termUdp() { if(!useDaemon) return; if(sd < 0) return; close(sd); sd = -1; } /* ******************************* */ static void deleteRRD(char *basePath, char *key) { char path[512]; int i; safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s%s.rrd", basePath, key); /* Avoid path problems */ for(i=strlen(basePath); i 0 ? dumpHours : DEFAULT_RRD_HOURS); argv[argc++] = minStr; safe_snprintf(__FILE__, __LINE__, maxStr, sizeof(maxStr), "RRA:MAX:%.1f:1:%d", 0.5, dumpHours > 0 ? dumpHours : DEFAULT_RRD_HOURS); argv[argc++] = maxStr; if(dumpDays > 0) { safe_snprintf(__FILE__, __LINE__, daysStr, sizeof(daysStr), "RRA:AVERAGE:%.1f:%d:%d", 0.5, value1, dumpDays * 24); argv[argc++] = daysStr; } /* Compute the rollup - how many rrdDumpInterval seconds interval are in a day */ value1 = (24*60*60 + rrdDumpInterval - 1) / rrdDumpInterval; if(dumpMonths > 0) { safe_snprintf(__FILE__, __LINE__, monthsStr, sizeof(monthsStr), "RRA:AVERAGE:%.1f:%d:%d", 0.5, value1, dumpMonths * 30); argv[argc++] = monthsStr; } safe_snprintf(__FILE__, __LINE__, tempStr, sizeof(tempStr), "RRA:HWPREDICT:1440:0.1:0.0035:20"); argv[argc++] = tempStr; #if DEBUG if(shownCreate == 0) { char buf[LEN_GENERAL_WORK_BUFFER]; int i; shownCreate=1; memset(buf, 0, sizeof(buf)); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s", argv[4]); for (i=5; i 0 { if(checkLast(path) >= rrdTime) traceEventRRDebug(0, "WARNING rrd_update not performed (RRD already updated)"); } #endif argc = 0; argv[argc++] = "rrd_update"; argv[argc++] = path; safe_snprintf(__FILE__, __LINE__, cmd, sizeof(cmd), "%u:%llu", (unsigned int)rrdTime, (unsigned long long)value); argv[argc++] = cmd; accessMutex(&rrdMutex, "rrd_update"); optind=0; /* reset gnu getopt */ opterr=0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); addRrdDelay(); rc = rrd_update(argc, argv); numRRDUpdates++; numTotalRRDUpdates++; if(rrd_test_error()) { int x; char *rrdError; traceEventRRDebugARGV(3); numRRDerrors++; rrdError = rrd_get_error(); if(rrdError != NULL) { traceEvent(CONST_TRACE_WARNING, "RRD: rrd_update(%s) error: %s", path, rrdError); traceEvent(CONST_TRACE_NOISY, "RRD: call stack (counter created: %d):", createdCounter); for (x = 0; x < argc; x++) traceEvent(CONST_TRACE_NOISY, "RRD: argv[%d]: %s", x, argv[x]); if(!strcmp(rrdError, "error: illegal attempt to update using time")) { char errTimeBuf1[32], errTimeBuf2[32], errTimeBuf3[32]; struct tm workT; time_t rrdLast = checkLast(path); strftime(errTimeBuf1, sizeof(errTimeBuf1), CONST_LOCALE_TIMESPEC, localtime_r(&myGlobals.actTime, &workT)); strftime(errTimeBuf2, sizeof(errTimeBuf2), CONST_LOCALE_TIMESPEC, localtime_r(&rrdTime, &workT)); strftime(errTimeBuf3, sizeof(errTimeBuf3), CONST_LOCALE_TIMESPEC, localtime_r(&rrdLast, &workT)); traceEvent(CONST_TRACE_WARNING, "RRD: actTime = %d(%s), rrdTime %d(%s), lastUpd %d(%s)", (int)myGlobals.actTime, errTimeBuf1, (int)rrdTime, errTimeBuf2, (int)rrdLast, rrdLast == -1 ? "rrdlast ERROR" : errTimeBuf3); } else if(strstr(rrdError, "is not an RRD file") || strstr(rrdError, "read operation failed")) { unlink(path); } else { char do_delete = 0; /* Delete empty RRD files */ if(stat(path, &statbuf) == 0) { if(statbuf.st_size == 0) do_delete = 1; } else do_delete = 1; if(do_delete) unlink(path); } rrd_clear_error(); } else { traceEventRRDebug(0, "rrd_update(%s, %s, %s)=%d", hostPath, key, cmd, rc); } } else if(0) { unsigned long step, ds_cnt; rrd_value_t *data,*datai, _total, _val; char **ds_namv, time_buf[32]; time_t start,end; safe_snprintf(__FILE__, __LINE__, time_buf, sizeof(time_buf), "%u", rrdTime); argc = 0; argv[argc++] = "rrd_fetch"; argv[argc++] = path; argv[argc++] = "FAILURES"; argv[argc++] = "--start"; argv[argc++] = time_buf; argv[argc++] = "--end"; argv[argc++] = time_buf; accessMutex(&rrdMutex, "rrd_fetch"); optind=0; /* reset gnu getopt */ opterr=0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); addRrdDelay(); rc = rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &ds_namv, &data); releaseMutex(&rrdMutex); if(rc != -1) { datai = data, _total = 0; for(i = start; i <= end; i += step) { _val = *(datai++); if(_val > 0) _total += _val; } for(i=0;i rrdpmaxDelay) rrdpmaxDelay = elapsed; #endif } } /* ******************************* */ static void updateCounter(char *hostPath, char *key, Counter value, char short_step) { /* traceEvent(CONST_TRACE_INFO, "updateCounter: [%s][%s]", hostPath, key); */ updateRRD(hostPath, key, value, 1, short_step); } /* ******************************* */ static void updateGauge(char *hostPath, char *key, Counter value, char short_step) { /* traceEvent(CONST_TRACE_INFO, "RRD: %s = %u", key, (unsigned long)value); */ updateRRD(hostPath, key, value, 0, short_step); } /* ******************************* */ static void updateTrafficCounter(char *hostPath, char *key, TrafficCounter *counter, char short_step) { if(counter->modified) { updateCounter(hostPath, key, counter->value, short_step); counter->modified = 0; } } /* ******************************* */ #ifndef WIN32 static void setGlobalPermissions(int permissionsFlag) { switch (permissionsFlag) { case CONST_RRD_PERMISSIONS_GROUP: myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_GROUP; myGlobals.rrdUmask = CONST_RRD_UMASK_GROUP; break; case CONST_RRD_PERMISSIONS_EVERYONE: myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_EVERYONE; myGlobals.rrdUmask = CONST_RRD_UMASK_EVERYONE; break; default: myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_PRIVATE; myGlobals.rrdUmask = CONST_RRD_UMASK_PRIVATE; break; } } #endif /* ******************************* */ static void commonRRDinit(void) { char value[1024]; #ifdef WIN32 get_serial(&driveSerial); #endif initUdp(); shownCreate = 0; #ifdef MAX_RRD_CYCLE_BUFFER if(rrdcycleBufferInit == 0) { rrdcycleBufferCount = 0; rrdcycleBufferInit = 1; memset(&rrdcycleBuffer, 0, sizeof(rrdcycleBuffer)); } #endif #ifdef MAX_RRD_PROCESS_BUFFER if(rrdprocessBufferInit == 0) { rrdprocessBufferCount = 0; rrdprocessBufferInit = 1; memset(&rrdprocessBuffer, 0, sizeof(rrdprocessBuffer)); } #endif if(fetchPrefsValue("rrd.dataDumpInterval", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_INTERVAL); storePrefsValue("rrd.dataDumpInterval", value); dumpInterval = DEFAULT_RRD_INTERVAL; } else { dumpInterval = atoi(value); } if(fetchPrefsValue("rrd.dumpShortInterval", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_SHORT_INTERVAL); storePrefsValue("rrd.dumpShortInterval", value); dumpShortInterval = DEFAULT_RRD_SHORT_INTERVAL; } else { dumpShortInterval = atoi(value); } if(fetchPrefsValue("rrd.dataDumpHours", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_HOURS); storePrefsValue("rrd.dataDumpHours", value); dumpHours = DEFAULT_RRD_HOURS; } else { dumpHours = atoi(value); } if(fetchPrefsValue("rrd.dataDumpDays", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_DAYS); storePrefsValue("rrd.dataDumpDays", value); dumpDays = DEFAULT_RRD_DAYS; } else { dumpDays = atoi(value); } if(fetchPrefsValue("rrd.dataDumpMonths", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_MONTHS); storePrefsValue("rrd.dataDumpMonths", value); dumpMonths = DEFAULT_RRD_MONTHS; } else { dumpMonths = atoi(value); } if(fetchPrefsValue("rrd.rrdDumpDelay", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_DUMP_DELAY); storePrefsValue("rrd.rrdDumpDelay", value); dumpDelay = DEFAULT_RRD_DUMP_DELAY; } else dumpDelay = atoi(value); if(fetchPrefsValue("rrd.dataDumpDomains", value, sizeof(value)) == -1) { storePrefsValue("rrd.dataDumpDomains", "0"); dumpDomains = 0; } else { dumpDomains = atoi(value); } if(fetchPrefsValue("rrd.dataDumpFlows", value, sizeof(value)) == -1) { storePrefsValue("rrd.dataDumpFlows", "0"); dumpFlows = 0; } else { dumpFlows = atoi(value); } if(fetchPrefsValue("rrd.dataDumpHosts", value, sizeof(value)) == -1) { storePrefsValue("rrd.dataDumpHosts", "0"); dumpHosts = 0; } else { dumpHosts = atoi(value); } if(fetchPrefsValue("rrd.dataDumpInterfaces", value, sizeof(value)) == -1) { storePrefsValue("rrd.dataDumpInterfaces", "1"); dumpInterfaces = 1; } else { dumpInterfaces = atoi(value); } if(fetchPrefsValue("rrd.dumpASs", value, sizeof(value)) == -1) { storePrefsValue("rrd.dumpASs", "1"); dumpASs = 1; } else { dumpASs = atoi(value); } if(fetchPrefsValue("rrd.enableAberrant", value, sizeof(value)) == -1) { storePrefsValue("rrd.enableAberrant", "1"); enableAberrant = 1; } else { enableAberrant = atoi(value); } if(fetchPrefsValue("rrd.dataDumpMatrix", value, sizeof(value)) == -1) { storePrefsValue("rrd.dataDumpMatrix", "0"); dumpMatrix = 0; } else { dumpMatrix = atoi(value); } if(hostsFilter != NULL) free(hostsFilter); if(fetchPrefsValue("rrd.hostsFilter", value, sizeof(value)) == -1) { int i; value[0] = '\0'; for(i=0; i> 24) & 0xff), (int) ((network >> 16) & 0xff), (int) ((network >> 8) & 0xff), (int) ((network >> 0) & 0xff), (int) ((netmask >> 24) & 0xff), (int) ((netmask >> 16) & 0xff), (int) ((netmask >> 8) & 0xff), (int) ((netmask >> 0) & 0xff)); if(value[0] != '\0') strcat(value, ","); strcat(value, buf); } hostsFilter = strdup(value); storePrefsValue("rrd.hostsFilter", hostsFilter); /* traceEvent(CONST_TRACE_INFO, "====> RRD: numLocalNetworks=%d [%s]", myGlobals.numLocalNetworks, value); */ } else { hostsFilter = strdup(value); } if(fetchPrefsValue("rrd.dataDumpDetail", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", CONST_RRD_DETAIL_DEFAULT); storePrefsValue("rrd.dataDumpDetail", value); dumpDetail = CONST_RRD_DETAIL_DEFAULT; } else { dumpDetail = atoi(value); } if(fetchPrefsValue("rrd.rrdPath", value, sizeof(value)) == -1) { char *thePath = "/rrd"; int len = strlen(myGlobals.dbPath)+strlen(thePath)+16, idx = 0; if(myGlobals.rrdPath) free(myGlobals.rrdPath); myGlobals.rrdPath = (char*)malloc(len); #ifdef WIN32 safe_snprintf(__FILE__, __LINE__, myGlobals.rrdPath, len, "%s/%u%s", &myGlobals.dbPath[idx], driveSerial, thePath); revertSlashIfWIN32(myGlobals.rrdPath, 0); #else safe_snprintf(__FILE__, __LINE__, myGlobals.rrdPath, len, "%s%s", &myGlobals.dbPath[idx], thePath); #endif len = strlen(myGlobals.rrdPath); if(myGlobals.rrdPath[len-1] == '/') myGlobals.rrdPath[len-1] = '\0'; storePrefsValue("rrd.rrdPath", myGlobals.rrdPath); } else { int vlen = strlen(value)+1; myGlobals.rrdPath = (char*)malloc(vlen); unescape(myGlobals.rrdPath, vlen, value); } #ifndef WIN32 if(fetchPrefsValue("rrd.permissions", value, sizeof(value)) == -1) { safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_PERMISSIONS); storePrefsValue("rrd.permissions", value); dumpPermissions = DEFAULT_RRD_PERMISSIONS; } else { dumpPermissions = atoi(value); } setGlobalPermissions(dumpPermissions); traceEvent(CONST_TRACE_INFO, "RRD: Mask for new directories is %04o", myGlobals.rrdDirectoryPermissions); umask(myGlobals.rrdUmask); traceEvent(CONST_TRACE_INFO, "RRD: Mask for new files is %04o", myGlobals.rrdUmask); #endif #ifdef RRD_DEBUG traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: Parameters:"); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpInterval %d seconds", dumpInterval); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpShortInterval %d seconds", dumpShortInterval); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpHours %d hours by %d seconds", dumpHours, dumpInterval); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDays %d days by hour", dumpDays); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpMonths %d months by day", dumpMonths); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDomains %s", dumpDomains == 0 ? "no" : "yes"); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpFlows %s", dumpFlows == 0 ? "no" : "yes"); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpHosts %s", dumpHosts == 0 ? "no" : "yes"); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpInterfaces %s", dumpInterfaces == 0 ? "no" : "yes"); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpASs %s", dumpASs == 0 ? "no" : "yes"); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpMatrix %s", dumpMatrix == 0 ? "no" : "yes"); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDetail %s", dumpDetail == FLAG_RRD_DETAIL_HIGH ? "high" : (dumpDetail == FLAG_RRD_DETAIL_MEDIUM ? "medium" : "low")); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: hostsFilter %s", hostsFilter); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: rrdPath %s", myGlobals.rrdPath); #ifndef WIN32 traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: umask %04o", myGlobals.rrdUmask); traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: DirPerms %04o", myGlobals.rrdDirectoryPermissions); #endif #endif /* RRD_DEBUG */ if (MAX_NUM_ENTRIES > CONST_NUM_BAR_COLORS) traceEvent(CONST_TRACE_WARNING, "RRD: Too few colors defined in rrd_colors - graphs could be truncated"); updateUdpParams(); initialized = 1; } /* ****************************** */ #undef option_timespan #define option_timespan(theStartTime, theLabel, selected) \ safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), \ "\n", \ "rrdPlugin", rrdIP, rrdInterface, rrdName, (unsigned int)theStartTime, (unsigned int)the_time, buf1, buf2, \ (selected == 1) ? "selected" : "", theLabel); sendString(buf); /* ****************************** */ static void arbitraryAction(char *rrdName, char *rrdInterface, char *rrdIP, char *_startTime, char *_endTime, char *rrdCounter, char *rrdTitle, char _which, char *mode) { int i, len, rc=0, argc = 0, argc1 = 0, countOK=0, countZERO=0; char buf[LEN_GENERAL_WORK_BUFFER], rrdKey[64], *startTime, *endTime, time_buf[32]; time_t the_time; struct tm *the_tm; startTime = _startTime, endTime = _endTime; if(atol(endTime) == 0) { snprintf(time_buf, sizeof(time_buf), "%u", (u_int)time(NULL)); endTime = time_buf; } if(atol(startTime) > atol(endTime)) { startTime = endTime; } if(!strcmp(mode, "zoom")) { char buf1[LEN_GENERAL_WORK_BUFFER], buf2[LEN_GENERAL_WORK_BUFFER]; sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0); escape(buf1, sizeof(buf1), rrdCounter); escape(buf2, sizeof(buf2), rrdTitle); sendString("
\n"); /* *************************************** */ /* Graph time and zoom: code courtesy of the Cacti (http://www.cacti.net) project. */ sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n

\n

\n\n
\nPresets: \n"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n", rrdIP, rrdInterface, rrdName, startTime, endTime, buf1, buf2); sendString(buf); sendString(" From:\n\n\n"); sendString(" To:\n\n\n" "\n\n
\n

\n"); /* *************************************** */ sendString("\n" "
\n"); sendString("
\n"); /* NOTE: If the graph size changes, please update the zoom.js file (search for L.Deri) */ safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\"graph
\n", rrdPluginInfo->pluginURLname, rrdIP, rrdInterface, rrdName, startTime, endTime, buf1, buf2); sendString(buf); sendString("\n\n"); sendString("\n"); printHTMLtrailer(); return; } memset(&buf, 0, sizeof(buf)); memset(&rrdKey, 0, sizeof(rrdKey)); /* Security check... it's a file name */ if(fileSanityCheck(rrdName, "arbitrary rrd request", 1) != 0) { traceEvent(CONST_TRACE_ERROR, "SECURITY: Invalid arbitrary rrd request(filename)... ignored"); return; } if(fileSanityCheck(rrdInterface, "arbitrary rrd request", 1) != 0) { traceEvent(CONST_TRACE_ERROR, "SECURITY: Invalid arbitrary rrd request(interface)... ignored"); return; } if(rrdIP[0] == '\0') { /* Interface level */ safe_snprintf(__FILE__, __LINE__, rrdKey, sizeof(rrdKey), "interfaces/%s/", rrdInterface); } else { /* Security check... it's an ip - 0..9 a..f . and : ONLY */ if(ipSanityCheck(rrdIP, "arbitrary rrd request", 1) != 0) { traceEvent(CONST_TRACE_ERROR, "SECURITY: Invalid arbitrary rrd request(ip)... ignored (sanitized: %s)", rrdIP); return; } len=strlen(rrdIP); for(i=0; i/" CONST_PLUGINS_HEADER "%s?action=" CONST_ARBITRARY_RRDREQUEST "&" CONST_ARBITRARY_IP "=%s" "&" CONST_ARBITRARY_INTERFACE "=%s" "&" CONST_ARBITRARY_FILE "=%s" "&start=%s" "&end=%s" "&counter=%s" "&title=%s

\n", rrdPluginInfo->pluginURLname, rrdIP, rrdInterface, rrdName, startTime, endTime, buf1, buf2); sendString(buf); printHTMLtrailer(); return; } if((_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) || (_which == CONST_ARBITRARY_RRDREQUEST_FETCHMECSV[0])) { char *argv[32], *argv1[8], rptTime[32], startWorkTime[32], path[128], **ds_namv; time_t start=0,end=time(NULL)+1, startTimeFound = 0; unsigned long step=0, ds_cnt, ii; rrd_value_t *data,*datai, _val; struct tm workT; memset(&path, 0, sizeof(path)); memset(&rptTime, 0, sizeof(rptTime)); memset(&startWorkTime, 0, sizeof(startWorkTime)); if(!strcmp(rrdName, "throughput")) { #ifdef WIN32 safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s%s.rrd", myGlobals.spoolPath, driveSerial, rrdKey, rrdName); #else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.spoolPath, rrdKey, rrdName); #endif } else safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.rrdPath, rrdKey, rrdName); if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) { sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD data dump", NULL, 0); sendString("

For: "); sendString(path); sendString("

"); } else { sendHTTPHeader(FLAG_HTTP_TYPE_TEXT, 0, 1); sendString("\"file\",\""); sendString(path); sendString("\"\n\n"); } argv[argc++] = "rrd_fetch"; argv[argc++] = path; argv[argc++] = "AVERAGE"; if((startTime != NULL) && (startTime[0] == '0') && (startTime[1] == '\0')) { argv1[argc1++] = "rrd_first"; argv1[argc1++] = path; startTimeFound = rrd_first(argc1, argv1); if(startTimeFound != ((time_t)-1)) { safe_snprintf(__FILE__, __LINE__, startWorkTime, sizeof(startWorkTime), "%u", startTimeFound); argv[argc++] = "--start"; argv[argc++] = startWorkTime; } } else if(startTime != NULL) { argv[argc++] = "--start"; argv[argc++] = startTime; } if((endTime != NULL) && (endTime[0] != '\0')) { argv[argc++] = "--end"; argv[argc++] = endTime; } optind=0; /* reset gnu getopt */ opterr=0; /* no error messages */ fillupArgv(argc, sizeof(argv)/sizeof(char*), argv); rrd_clear_error(); accessMutex(&rrdMutex, "arbitrary rrd_fetch"); rc = rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &ds_namv, &data); releaseMutex(&rrdMutex); if(rc == -1) { traceEventRRDebugARGV(3); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sError retrieving rrd data, %s%s\n", rrd_get_error() ? rrd_get_error() : "", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "

" : "", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "

" : ""); sendString(buf); return; } if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) { sendString("
\n" "\n" "" "\n"); } datai = data; for(ii = start; ii <= end; ii += step) { _val = *(datai++); if(_val > 0) { countOK++; strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r((time_t *)&ii, &workT)); if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) { safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\n", rptTime, ii, _val); } else { safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\"%s\",%u,%.6g\n", rptTime, ii, _val); } sendString(buf); } else { countZERO++; } } for(i=0;i\n" "\n"); } /* Closing comments... */ safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "\n\n%sNotes%s\n" "%s%d data points reported, %d skipped%s\n\n", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "

" : "\"", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "

\n
    " : "\"", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\n\"", countOK, countZERO, (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\""); sendString(buf); if(startTimeFound != ((time_t)-1)) { strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r(&startTimeFound, &workT)); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sFound %s (%u) as the first (detail) data point%s\n", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\"", rptTime, startTimeFound, (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\""); } else if(start > 0) { strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r(&start, &workT)); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sFetch found %s (%u) as the first %s data point%s\n", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\"", rptTime, start, step <= dumpInterval ? "detail" : "summary", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\""); } sendString(buf); strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r(&end, &workT)); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sFetch found %s (%u) as the last data point%s\n", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\"", rptTime, end, (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\""); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sStep is %u seconds%s\n", (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • " : "\"", step, (_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "
  • \n
" : "\""); sendString(buf); sendString((_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "

" : "\""); sendString("This request is roughly equivalent to: "); sendString((_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "" : ""); sendString("rrdtool fetch"); for(i=1; i

" : "\""); if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) printHTMLtrailer(); return; } rc = graphCounter(rrdKey, rrdName, rrdTitle, rrdCounter, startTime, endTime, "arbitrary"); return; } /* ****************************** */ static void statisticsPage(void) { char buf[1024]; #ifdef MAX_RRD_PROCESS_BUFFER float pminDelay=99999.0, pmaxDelay=0.0; int i; float /*stddev:*/ pM, pT, pQ, pR, pSD; #endif memset(&buf, 0, sizeof(buf)); sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("RRD Statistics", NULL, 0); sendString("
Sample date/timeValue
%s%u%.6g
\n" "" "\n"); sendString("\n", (unsigned long)numRRDCycles); sendString(buf); sendString("\n", (unsigned long)numTotalRRDUpdates); sendString(buf); sendString("\n", (unsigned long)numRRDerrors); sendString(buf); sendString("\n", (unsigned long)rrdGraphicRequests); sendString(buf); sendString("
ItemCount
Cycles"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu
Files Updated"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu
Update Errors"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu
Graphic Requests"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu
\n
\n"); #ifdef MAX_RRD_PROCESS_BUFFER printSectionTitle("Per-RRD Processing times"); sendString("
\n
" "

These numbers are the elapsed time (in seconds) per RRD update. " "The computations are based only on the most recent " xstr(MAX_RRD_PROCESS_BUFFER) " RRDs processed.

\n" "

'Processing' time is the elapsed time between starting and finishing " "updateRRD(). Errors may cause processing to be abandoned and those RRD " "updates are not counted in the 'processing' averages.

\n" "

If the RRD does not already exist, it will be created (along with any " "necessary directories), so the reported values may include a mix of " "short and long duration calls.

\n" "

Small averages are good, especially if the standard deviation is small " "(standard deviation is a measurement of the variability of the actual values " "around the average).

\n" "

 

\n" "
\n"); if(rrdprocessBufferCount >= MAX_RRD_PROCESS_BUFFER) { sendString("
\n" "" "\n"); for(i=0; i pmaxDelay) pmaxDelay = rrdprocessBuffer[i]; if(rrdprocessBuffer[i] < pminDelay) pminDelay = rrdprocessBuffer[i]; if(i==0) { pM = rrdprocessBuffer[0]; pT = 0.0; } else { pQ = rrdprocessBuffer[i] - pM; pR = pQ / (float)(i+1); pM += pR; pT = pT + i * pQ * pR; } } pSD = sqrtf(pT / (MAX_RRD_PROCESS_BUFFER - 1)); pXBAR /*average*/ = pM; sendString("\n", pminDelay); sendString(buf); sendString("\n", pXBAR); sendString(buf); sendString("\n", pmaxDelay); sendString(buf); sendString("\n", pSD); sendString(buf); sendString("\n", rrdpmaxDelay); sendString(buf); sendString("
ItemTime
Minimum"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Average"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Maximum"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Standard Deviation"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Maximum ever"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
\n
\n"); } else { printNoDataYet(); } #endif /* MAX_RRD_PROCESS_BUFFER */ #ifdef MAX_RRD_CYCLE_BUFFER printSectionTitle("Per-Cycle Processing times"); sendString("
\n
" "

These numbers are the elapsed time (in seconds) per RRD update cycle. " "The computations are based only on the most recent " xstr(MAX_RRD_CYCLE_BUFFER) " cycles executed.

\n" "

'Processing' time is the elapsed time between waking and returning to " "sleep in rrdMainLoop(). The currently executing cycle (if one) is not " "included.

" "

 

\n" "
\n"); if(rrdcycleBufferCount >= MAX_RRD_CYCLE_BUFFER) { sendString("
\n" "" "\n"); for(i=0; i pmaxDelay) pmaxDelay = rrdcycleBuffer[i]; if(rrdcycleBuffer[i] < pminDelay) pminDelay = rrdcycleBuffer[i]; if(i==0) { pM = rrdcycleBuffer[0]; pT = 0.0; } else { pQ = rrdcycleBuffer[i] - pM; pR = pQ / (float)(i+1); pM += pR; pT = pT + i * pQ * pR; } } pSD = sqrtf(pT / (MAX_RRD_CYCLE_BUFFER - 1)); pXBAR /*average*/ = pM; sendString("\n", pminDelay); sendString(buf); sendString("\n", pXBAR); sendString(buf); sendString("\n", pmaxDelay); sendString(buf); sendString("\n", pSD); sendString(buf); sendString("\n", rrdcmaxLength); sendString(buf); sendString("
ItemTime
Minimum"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Average"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Maximum"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Standard Deviation"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
Maximum ever"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f
\n
\n"); } else { printNoDataYet(); } #endif /* MAX_RRD_CYCLE_BUFFER */ } /* ****************************** */ static void arbitraryActionPage(void) { int idx, count, rc; char buf[1024], dirPath[256], rrdPath[512], startTime[32], endTime[32]; DIR* directoryPointer=NULL; struct dirent* dp; struct stat statBuf; time_t now = time(NULL); memset(&buf, 0, sizeof(buf)); memset(&dirPath, 0, sizeof(dirPath)); memset(&rrdPath, 0, sizeof(rrdPath)); memset(&startTime, 0, sizeof(startTime)); memset(&endTime, 0, sizeof(endTime)); safe_snprintf(__FILE__, __LINE__, startTime, sizeof(startTime), "%u", now-12*3600); safe_snprintf(__FILE__, __LINE__, endTime, sizeof(endTime), "%u", now); sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1); printHTMLheader("Arbitrary RRD Actions", NULL, 0); safe_snprintf(__FILE__, __LINE__, dirPath, sizeof(dirPath), "%s/interfaces", myGlobals.rrdPath); revertSlashIfWIN32(dirPath, 0); directoryPointer = opendir(dirPath); if(directoryPointer == NULL) { sendString("

No rrds found - check configuration.

\n"); return; } safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "
" "

This allows you to see and/or create a graph of an arbitrary rrd file.

\n" "
\n" "\n" "\n" "\n" "\n" "\n\n" "\n\n" "\n\n" "\n" "\n\n\n" "\n" "\n\n" "\n" "\n" "\n
Action" "" " Create the graph - this is returned as a png file and will display ONLY the graph, " "without any html headings.
\n" "" " Display the url to request the graph
\n" "" " Retrieve rrd data in table form
\n" "" " Retrieve rrd data as CSV" "
File" "" "
\n

Note: The drop down list shows all possible files - many (most) (all) " "of which may not be available for a specific host. Further, the list is " "based on the -p | --protocols parameter of this ntop run and may not " "include files created during ntop runs with other -p | --protocols " "parameter settings.

\n
Interface"); count = 0; while((dp = readdir(directoryPointer)) != NULL) { if(dp->d_name[0] != '.') { safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s", myGlobals.rrdPath, dp->d_name); rc = stat(rrdPath, &statBuf); if((rc == 0) && ((statBuf.st_mode & S_IFDIR) == S_IFDIR)) { count++; safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s
\n", dp->d_name, count == 1 ? "CHECKED" : "", dp->d_name); sendString(buf); } } } if(count == 0) sendString("No RRD interface files available."); closedir(directoryPointer); sendString("
Host IP address" "" "  Leave blank to create a per-interface graph.
\n" "

A note about time specification: You may specify time in a number of ways - please " "see \"AT-STYLE TIME SPECIFICATION\" in the rrdfetch man page for the full details. Here " "are some examples:

\n
    \n" "
  • Specific values: Most common formats are understood, including numerical and character " "date formats, such as Oct 12 - October 12th of " "the current year, 10/12/2005, etc.
  • \n" "
  • Relative time: now-1d (now minus one day) Several time units can be combined together, " "such as -5mon1w2d
  • \n" "
  • Seconds since epoch: 1110286800 (this specific value is equivalent to " "Tue 08 Mar 2005 07:00:00 AM CST
  • \n" "
\n" "

Don't bother trying to break these - we just pass it through to rrdtool. If you want to " "play, there are a thousand lines in parsetime.c just waiting for you.

\n" "

A note about RRD files: You may remember that the rrd file contains data stored " "at different resolutions - for ntop this is typically every 5 minutes, hourly, and daily. " "rrdfetch automatically picks the RRA (Round-Robin Archive) which provides the 'best' coverage " "of the time span you request. Thus, if you request a start time which is before the number " "of 5 minute samples stored in RRA[0], you will 'magically' see the data from RRA[1], the " "hourly samples. Other than changing the start/end times, there is no way to force rrdfetch " "to select a specific RRA.

\n" "

Two notes for the fetch options:

\n" "

Counter values are normalized to per-second rates. To get the (approximate) value of a " "counter for the entire interval, you need to multipy the per-second rate by the number of " "seconds in the interval (this is the step, reported at the bottom of the output page).

\n" "

If start time is left blank, the default is --start end-1d. To force a dump from the " "earliest detail point in the rrd, use the special value 0.

Start" "
\n" "
End" "
For graphs only
Legend" "
\n" "This is the 'name' of the counter being displayed, e.g. eth1 Mail bytes. " "It appears at the bottom left as the legend for the colored bars
(optional) Title to appear above the graph
 
"); if(count > 0) sendString(""); sendString("
 
\n
\n
\n"); } /* ****************************** */ static void printRRDPluginTrailer(void) { printPluginTrailer(NULL, "RRDtool " "was created by " "" "Tobi Oetiker"); printHTMLtrailer(); } /* ****************************** */ static time_t parse_date(char* value) { /* 2006-07-11 10:06 */ struct tm _tm; memset(&_tm, 0, sizeof(_tm)); if(sscanf(value, "%d-%d-%d %d:%d", &_tm.tm_year, &_tm.tm_mon, &_tm.tm_mday, &_tm.tm_hour, &_tm.tm_min) == 5) { --_tm.tm_mon, _tm.tm_year -= 1900; return(mktime(&_tm)); } else return(0); } /* ****************************** */ static void handleRRDHTTPrequest(char* url) { char buf[1024], *strtokState, *mainState, *urlPiece, rrdKey[64], rrdName[64], rrdTitle[128], rrdCounter[64], startTime[32], endTime[32], rrdPrefix[32], rrdIP[32], rrdInterface[64], rrdPath[512], mode[32], cluster[32]; u_char action = FLAG_RRD_ACTION_NONE; char _which; int _dumpDomains, _dumpFlows, _dumpHosts, _dumpInterfaces, _dumpASs, _enableAberrant, _dumpMatrix, _dumpDetail, _dumpInterval, _dumpShortInterval, _dumpHours, _dumpDays, _dumpMonths, graphId; int i, len, idx; time_t date1 = 0, date2 = 0; char * _hostsFilter; #ifndef WIN32 int _dumpPermissions; #endif time_t now = time(NULL); if(initialized == 0) commonRRDinit(); /* Specialty pages */ if(strncasecmp(url, CONST_RRD_STATISTICS_HTML, strlen(CONST_RRD_STATISTICS_HTML)) == 0) { statisticsPage(); printRRDPluginTrailer(); return; } else if(strncasecmp(url, CONST_RRD_ARBGRAPH_HTML, strlen(CONST_RRD_ARBGRAPH_HTML)) == 0) { arbitraryActionPage(); printRRDPluginTrailer(); return; } /* Initial values - remember, for checkboxes these need to be OFF (there's no html UNCHECKED option) */ _dumpDomains=0; _dumpFlows=0; _dumpHosts=0; _dumpInterfaces=0; _dumpASs=0; _enableAberrant=0; _dumpMatrix=0; _dumpDetail=CONST_RRD_DETAIL_DEFAULT; _dumpInterval=DEFAULT_RRD_INTERVAL; _dumpShortInterval=DEFAULT_RRD_SHORT_INTERVAL; _dumpHours=DEFAULT_RRD_HOURS; _dumpDays=DEFAULT_RRD_DAYS; _dumpMonths=DEFAULT_RRD_MONTHS; _hostsFilter = NULL; #ifndef WIN32 _dumpPermissions = DEFAULT_RRD_PERMISSIONS; #endif _which=0; memset(&buf, 0, sizeof(buf)); memset(&rrdKey, 0, sizeof(rrdKey)); memset(&rrdName, 0, sizeof(rrdName)); memset(&rrdTitle, 0, sizeof(rrdTitle)); memset(&rrdCounter, 0, sizeof(rrdCounter)); memset(&startTime, 0, sizeof(startTime)); memset(&endTime, 0, sizeof(endTime)); memset(&rrdPrefix, 0, sizeof(rrdPrefix)); memset(&rrdIP, 0, sizeof(rrdIP)); memset(&rrdInterface, 0, sizeof(rrdInterface)); memset(&rrdPath, 0, sizeof(rrdPath)); memset(&mode, 0, sizeof(mode)); memset(&cluster, 0, sizeof(cluster)); safe_snprintf(__FILE__, __LINE__, startTime, sizeof(startTime), "%u", now-12*3600); safe_snprintf(__FILE__, __LINE__, endTime, sizeof(endTime), "%u", now); if((url != NULL) && (url[0] != '\0')) { unescape_url(url); /* traceEvent(CONST_TRACE_INFO, "RRD: URL=%s", url); */ urlPiece = strtok_r(url, "&", &mainState); while(urlPiece != NULL) { char *key, *value; key = strtok_r(urlPiece, "=", &strtokState); if(key != NULL) value = strtok_r(NULL, "=", &strtokState); else value = NULL; /* traceEvent(CONST_TRACE_INFO, "RRD: key(%s)=%s", key, value); */ if(value && key) { if(strcmp(key, "action") == 0) { if(strcmp(value, "graph") == 0) action = FLAG_RRD_ACTION_GRAPH; else if(strcmp(value, CONST_ARBITRARY_RRDREQUEST) == 0) action = FLAG_RRD_ACTION_ARBITRARY; else if(strcmp(value, "graphSummary") == 0) action = FLAG_RRD_ACTION_GRAPH_SUMMARY; else if(strcmp(value, "netflowSummary") == 0) action = FLAG_RRD_ACTION_NF_SUMMARY; else if(strcmp(value, "interfaceSummary") == 0) action = FLAG_RRD_ACTION_IF_SUMMARY; else if(strcmp(value, "netflowIfSummary") == 0) action = FLAG_RRD_ACTION_NF_IF_SUMMARY; else if(strcmp(value, "list") == 0) action = FLAG_RRD_ACTION_LIST; } else if(strcmp(key, "cluster") == 0) { safe_snprintf(__FILE__, __LINE__, cluster, sizeof(cluster), "%s", value); } else if(strcmp(key, "key") == 0) { safe_snprintf(__FILE__, __LINE__, rrdKey, sizeof(rrdKey), "%s", value); len = strlen(rrdKey); for(i=0; i FLAG_RRD_DETAIL_HIGH) _dumpDetail = FLAG_RRD_DETAIL_HIGH; if(_dumpDetail < FLAG_RRD_DETAIL_LOW) _dumpDetail = FLAG_RRD_DETAIL_LOW; } else if(strcmp(key, "dumpHosts") == 0) { _dumpHosts = 1; } else if(strcmp(key, "dumpInterfaces") == 0) { _dumpInterfaces = 1; } else if(strcmp(key, "dumpASs") == 0) { _dumpASs = 1; } else if(strcmp(key, "enableAberrant") == 0) { _enableAberrant = atoi(value); } else if(strcmp(key, "dumpMatrix") == 0) { _dumpMatrix = 1; #ifndef WIN32 } else if(strcmp(key, "permissions") == 0) { _dumpPermissions = atoi(value); if((_dumpPermissions != CONST_RRD_PERMISSIONS_PRIVATE) && (_dumpPermissions != CONST_RRD_PERMISSIONS_GROUP) && (_dumpPermissions != CONST_RRD_PERMISSIONS_EVERYONE)) { _dumpPermissions = DEFAULT_RRD_PERMISSIONS; } #endif } else if(strcmp(key, "which") == 0) { _which = value[0]; } else if(strcmp(key, "date1") == 0) { date1 = parse_date(value); } else if(strcmp(key, "date2") == 0) { date2 = parse_date(value); } } urlPiece = strtok_r(NULL, "&", &mainState); } if(date1 > 0) safe_snprintf(__FILE__, __LINE__, startTime, sizeof(startTime), "%d", date1); if(date2 > 0) safe_snprintf(__FILE__, __LINE__, endTime, sizeof(endTime), "%d", date2); if(action == FLAG_RRD_ACTION_NONE) { dumpInterval = _dumpInterval; if(dumpShortInterval != _dumpShortInterval) { int devIdx; dumpShortInterval = _dumpShortInterval; for(devIdx=0; devIdxYou must restart the rrd plugin for changes here to take affect.

\n"); else sendString("

Changes here will take effect when the plugin is started.

\n"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "
\n" "\n" "" "\n" "\n"); sendString("\n"); sendString("\n"); sendString("\n"); sendString("\n"); sendString(""); sendString("\n"); sendString("\n"); if(dumpHosts) { sendString("\n"); } /* ******************************** */ sendString("\n"); /* ******************************** */ sendString("\n"); /* ******************************** */ sendString("\n"); #ifndef WIN32 sendString("\n"); #endif sendString("\n" "
ItemDescription and Notes
Dump Interval" " seconds
Specifies how often data is stored permanently.
Throughput Granularity" " seconds
Specifies how often throughput data is stored permanently.
" "Note: if you change this value the throughput stats will be reset " "and past values will be lost. You've been warned!
Dump Hours" "
Specifies how many hours of 'interval' data is stored permanently.
Dump Days" "
Specifies how many days of hourly data is stored permanently.
Dump Months" "
Specifies how many months (30 days) of daily data is stored permanently.
WARNING: " "Changes to the above values will ONLY affect NEW rrds
RRD Update Delay" "
Specifies how many ms to wait between two consecutive RRD updates. Increase this value to distribute RRD load on I/O over the time. Note that a combination of large delays and many RRDs to update can slow down the RRD plugin performance
Data to Dump"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), " Domains
\n", dumpDomains ? "CHECKED" : "" ); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), " Flows
\n", dumpFlows ? "CHECKED" : "" ); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), " Hosts
\n", dumpHosts ? "CHECKED" : ""); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), " Interfaces
\n", dumpInterfaces ? "CHECKED" : ""); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), " ASs
\n", dumpASs ? "CHECKED" : ""); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), " Matrix
\n", dumpMatrix ? "CHECKED" : ""); sendString(buf); sendString("
Hosts Filter" "
A list of networks [e.g. 172.22.0.0/255.255.0.0,192.168.5.0/255.255.255.0]
" "separated by commas to which hosts that will be
" "saved must belong to. An empty list means that all the hosts will " "be stored on disk
RRD Detail"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Low\n", FLAG_RRD_DETAIL_LOW, (dumpDetail == FLAG_RRD_DETAIL_LOW) ? "CHECKED" : ""); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Medium\n", FLAG_RRD_DETAIL_MEDIUM, (dumpDetail == FLAG_RRD_DETAIL_MEDIUM) ? "CHECKED" : ""); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Full\n", FLAG_RRD_DETAIL_HIGH, (dumpDetail == FLAG_RRD_DETAIL_HIGH) ? "CHECKED" : ""); sendString(buf); sendString("
Detect Anomalies"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Yes\n", (enableAberrant == 1) ? "CHECKED" : ""); sendString(buf); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "No\n", (enableAberrant == 0) ? "CHECKED" : ""); sendString(buf); sendString("
Toggle RRD Aberrant Behavior support"); sendString("
RRD Files Path" ""); sendString("
NOTE:
  • The rrd files will be in a subdirectory structure, e.g.\n"); #ifdef WIN32 safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s\\interfaces\\interface-name\\12\\239\\98\\199\\xxxxx.rrd ", myGlobals.rrdPath); #else safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s/interfaces/interface-name/12/239/98/199/xxxxx.rrd ", myGlobals.rrdPath); #endif sendString(buf); sendString("to limit the number of files per subdirectory."); sendString("
  • Do not use the ':' character in the path as it is forbidded by rrd
File/Directory Permissions"); sendString("
    \n"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "
  • Private - ", CONST_RRD_PERMISSIONS_PRIVATE, (dumpPermissions == CONST_RRD_PERMISSIONS_PRIVATE) ? "CHECKED" : ""); sendString(buf); sendString("means that ONLY the ntop userid will be able to view the files
  • \n"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "
  • Group - ", CONST_RRD_PERMISSIONS_GROUP, (dumpPermissions == CONST_RRD_PERMISSIONS_GROUP) ? "CHECKED" : ""); sendString(buf); sendString("means that all users in the same group as the ntop userid will be able to view the rrd files.\n"); sendString("
    (this is a bad choice if ntop's group is 'nobody' along with many other service ids)
  • \n"); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "
  • Everyone - ", CONST_RRD_PERMISSIONS_EVERYONE, (dumpPermissions == CONST_RRD_PERMISSIONS_EVERYONE) ? "CHECKED" : ""); sendString(buf); sendString("means that everyone on the ntop host system will be able to view the rrd files.
  • \n"); sendString("

\nWARNING: Changing this setting affects only new files " "and directories! " "Unless you go back and fixup existing file and directory permissions:
\n" "
  • Users will retain access to any rrd file or directory they currently have " "access to even if you change to a more restrictive setting.
  • \n" "
  • Users will not gain access to any rrd file or directory they currently do not " "have access to even if you change to a less restrictive setting. Further, existing " "directory permissions may prevent them from reading new files created in existing " "directories.
  • \n" "
\n
 

 
\n
\n
\n"); sendString("
\n

Also:

\n
    "); for(i=0; rrdExtraPages[i].url != NULL; i++) { safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "
  • %s
  • \n", rrdPluginInfo->pluginURLname, rrdExtraPages[i].url, rrdExtraPages[i].descr); sendString(buf); } sendString("
\n"); printRRDPluginTrailer(); } /* ****************************** */ #ifdef MAKE_WITH_RRDSIGTRAP RETSIGTYPE rrdcleanup(int signo) { static int msgSent = 0; int i; void *array[20]; size_t size; char **strings; if(msgSent<10) { traceEvent(CONST_TRACE_FATALERROR, "RRD: caught signal %d %s", signo, signo == SIGHUP ? "SIGHUP" : signo == SIGINT ? "SIGINT" : signo == SIGQUIT ? "SIGQUIT" : signo == SIGILL ? "SIGILL" : signo == SIGABRT ? "SIGABRT" : signo == SIGFPE ? "SIGFPE" : signo == SIGKILL ? "SIGKILL" : signo == SIGSEGV ? "SIGSEGV" : signo == SIGPIPE ? "SIGPIPE" : signo == SIGALRM ? "SIGALRM" : signo == SIGTERM ? "SIGTERM" : signo == SIGUSR1 ? "SIGUSR1" : signo == SIGUSR2 ? "SIGUSR2" : signo == SIGCHLD ? "SIGCHLD" : #ifdef SIGCONT signo == SIGCONT ? "SIGCONT" : #endif #ifdef SIGSTOP signo == SIGSTOP ? "SIGSTOP" : #endif #ifdef SIGBUS signo == SIGBUS ? "SIGBUS" : #endif #ifdef SIGSYS signo == SIGSYS ? "SIGSYS" #endif : "other"); msgSent++; } #ifdef HAVE_BACKTRACE /* Don't double fault... */ /* signal(signo, SIG_DFL); */ /* Grab the backtrace before we do much else... */ size = backtrace(array, 20); strings = (char**)backtrace_symbols(array, size); traceEvent(CONST_TRACE_ERROR, "RRD: BACKTRACE: backtrace is:"); if(size < 2) { traceEvent(CONST_TRACE_ERROR, "RRD: BACKTRACE: **unavailable!"); } else { /* Ignore the 0th entry, that's our cleanup() */ for (i=1; ibytesSent.value > 0) || (el->bytesRcvd.value > 0)) { if(el->hostNumIpAddress[0] != '\0') { hostKey = el->hostNumIpAddress; if((numLocalNets > 0) && (el->hostIpAddress.hostFamily == AF_INET) /* IPv4 ONLY <-- FIX */ && (!__pseudoLocalAddress(&el->hostIpAddress.Ip4Address, networks, numLocalNets, NULL, NULL))) { return; } if((!myGlobals.runningPref.dontTrustMACaddr) && subnetPseudoLocalHost(el) && (el->ethAddressString[0] != '\0')) /* NOTE: MAC address is empty even for local hosts if this host has been learnt on a virtual interface such as the NetFlow interface */ hostKey = el->ethAddressString; } else { /* For the time being do not save IP-less hosts */ return; } adjHostName = dotToSlash(hostKey); safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName, adjHostName); mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions); traceEventRRDebug(2, "Updating %s [%s/%s]", hostKey, el->hostNumIpAddress, el->ethAddressString); updateTrafficCounter(rrdPath, "pktSent", &el->pktSent, 0); updateTrafficCounter(rrdPath, "pktRcvd", &el->pktRcvd, 0); updateTrafficCounter(rrdPath, "bytesSent", &el->bytesSent, 0); updateTrafficCounter(rrdPath, "bytesRcvd", &el->bytesRcvd, 0); if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) { updateTrafficCounter(rrdPath, "pktDuplicatedAckSent", &el->pktDuplicatedAckSent, 0); updateTrafficCounter(rrdPath, "pktDuplicatedAckRcvd", &el->pktDuplicatedAckRcvd, 0); updateTrafficCounter(rrdPath, "pktBroadcastSent", &el->pktBroadcastSent, 0); updateTrafficCounter(rrdPath, "bytesBroadcastSent", &el->bytesBroadcastSent, 0); updateTrafficCounter(rrdPath, "pktMulticastSent", &el->pktMulticastSent, 0); updateTrafficCounter(rrdPath, "bytesMulticastSent", &el->bytesMulticastSent, 0); updateTrafficCounter(rrdPath, "pktMulticastRcvd", &el->pktMulticastRcvd, 0); updateTrafficCounter(rrdPath, "bytesMulticastRcvd", &el->bytesMulticastRcvd, 0); updateTrafficCounter(rrdPath, "bytesLocSent", &el->bytesSentLoc, 0); updateTrafficCounter(rrdPath, "bytesRemSent", &el->bytesSentRem, 0); updateTrafficCounter(rrdPath, "bytesLocRcvd", &el->bytesRcvdLoc, 0); updateTrafficCounter(rrdPath, "bytesFromRemRcvd", &el->bytesRcvdFromRem, 0); updateTrafficCounter(rrdPath, "ipBytesSent", &el->ipBytesSent, 0); updateTrafficCounter(rrdPath, "ipBytesRcvd", &el->ipBytesRcvd, 0); updateTrafficCounter(rrdPath, "tcpLocSent", &el->tcpSentLoc, 0); updateTrafficCounter(rrdPath, "tcpRemSent", &el->tcpSentRem, 0); updateTrafficCounter(rrdPath, "udpLocSent", &el->udpSentLoc, 0); updateTrafficCounter(rrdPath, "udpRemSent", &el->udpSentRem, 0); updateTrafficCounter(rrdPath, "icmpSent", &el->icmpSent, 0); updateTrafficCounter(rrdPath, "tcpLocRcvd", &el->tcpRcvdLoc, 0); updateTrafficCounter(rrdPath, "tcpFromRemRcvd", &el->tcpRcvdFromRem, 0); updateTrafficCounter(rrdPath, "udpLocRcvd", &el->udpRcvdLoc, 0); updateTrafficCounter(rrdPath, "udpFromRemRcvd", &el->udpRcvdFromRem, 0); updateTrafficCounter(rrdPath, "icmpRcvd", &el->icmpRcvd, 0); updateTrafficCounter(rrdPath, "tcpFragmentsSent", &el->tcpFragmentsSent, 0); updateTrafficCounter(rrdPath, "tcpFragmentsRcvd", &el->tcpFragmentsRcvd, 0); updateTrafficCounter(rrdPath, "udpFragmentsSent", &el->udpFragmentsSent, 0); updateTrafficCounter(rrdPath, "udpFragmentsRcvd", &el->udpFragmentsRcvd, 0); updateTrafficCounter(rrdPath, "icmpFragmentsSent", &el->icmpFragmentsSent, 0); updateTrafficCounter(rrdPath, "icmpFragmentsRcvd", &el->icmpFragmentsRcvd, 0); updateTrafficCounter(rrdPath, "ipv6Sent", &el->ipv6Sent, 0); updateTrafficCounter(rrdPath, "ipv6Rcvd", &el->ipv6Rcvd, 0); if(el->nonIPTraffic) { updateTrafficCounter(rrdPath, "stpSent", &el->nonIPTraffic->stpSent, 0); updateTrafficCounter(rrdPath, "stpRcvd", &el->nonIPTraffic->stpRcvd, 0); updateTrafficCounter(rrdPath, "ipxSent", &el->nonIPTraffic->ipxSent, 0); updateTrafficCounter(rrdPath, "ipxRcvd", &el->nonIPTraffic->ipxRcvd, 0); updateTrafficCounter(rrdPath, "osiSent", &el->nonIPTraffic->osiSent, 0); updateTrafficCounter(rrdPath, "osiRcvd", &el->nonIPTraffic->osiRcvd, 0); updateTrafficCounter(rrdPath, "dlcSent", &el->nonIPTraffic->dlcSent, 0); updateTrafficCounter(rrdPath, "dlcRcvd", &el->nonIPTraffic->dlcRcvd, 0); updateTrafficCounter(rrdPath, "arp_rarpSent", &el->nonIPTraffic->arp_rarpSent, 0); updateTrafficCounter(rrdPath, "arp_rarpRcvd", &el->nonIPTraffic->arp_rarpRcvd, 0); updateTrafficCounter(rrdPath, "arpReqPktsSent", &el->nonIPTraffic->arpReqPktsSent, 0); updateTrafficCounter(rrdPath, "arpReplyPktsSent", &el->nonIPTraffic->arpReplyPktsSent, 0); updateTrafficCounter(rrdPath, "arpReplyPktsRcvd", &el->nonIPTraffic->arpReplyPktsRcvd, 0); updateTrafficCounter(rrdPath, "decnetSent", &el->nonIPTraffic->decnetSent, 0); updateTrafficCounter(rrdPath, "decnetRcvd", &el->nonIPTraffic->decnetRcvd, 0); updateTrafficCounter(rrdPath, "appletalkSent", &el->nonIPTraffic->appletalkSent, 0); updateTrafficCounter(rrdPath, "appletalkRcvd", &el->nonIPTraffic->appletalkRcvd, 0); updateTrafficCounter(rrdPath, "netbiosSent", &el->nonIPTraffic->netbiosSent, 0); updateTrafficCounter(rrdPath, "netbiosRcvd", &el->nonIPTraffic->netbiosRcvd, 0); updateTrafficCounter(rrdPath, "otherSent", &el->nonIPTraffic->otherSent, 0); updateTrafficCounter(rrdPath, "otherRcvd", &el->nonIPTraffic->otherRcvd, 0); } protoList = myGlobals.ipProtosList, idx=0; while(protoList != NULL) { char buf[64]; if(el->ipProtosList[idx] != NULL) { safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sSent", protoList->protocolName); updateTrafficCounter(rrdPath, buf, &el->ipProtosList[idx]->sent, 0); safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sRcvd", protoList->protocolName); updateTrafficCounter(rrdPath, buf, &el->ipProtosList[idx]->rcvd, 0); } idx++, protoList = protoList->next; } } if(dumpDetail == FLAG_RRD_DETAIL_HIGH) { updateCounter(rrdPath, "totPeersSent", el->totContactedSentPeers, 0); updateCounter(rrdPath, "totPeersRcvd", el->totContactedRcvdPeers, 0); if(el->protoIPTrafficInfos) { traceEventRRDebug(0, "Updating host %s", hostKey); safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/IP_", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName, adjHostName ); for(j=0; jprotoIPTrafficInfos[j]) { char key[128]; if(el->protoIPTrafficInfos[j] != NULL) { safe_snprintf(__FILE__, __LINE__, key, sizeof(key), "%sBytesSent", myGlobals.ipTrafficProtosNames[j]); updateCounter(rrdPath, key, el->protoIPTrafficInfos[j]->sentLoc.value+ el->protoIPTrafficInfos[j]->sentRem.value, 0); safe_snprintf(__FILE__, __LINE__, key, sizeof(key), "%sBytesRcvd", myGlobals.ipTrafficProtosNames[j]); updateCounter(rrdPath, key, el->protoIPTrafficInfos[j]->rcvdLoc.value+ el->protoIPTrafficInfos[j]->rcvdFromRem.value, 0); } } } } } if(adjHostName != NULL) free(adjHostName); } ntop_conditional_sched_yield(); /* Allow other threads to run */ return; } /* ****************************** */ static void rrdUpdateFcHostStats (HostTraffic *el, int devIdx) { char rrdPath[512]; char *adjHostName; char hostKey[128]; lockHostsHashMutex(el, "rrdUpdateFcHostStats"); if((el->bytesSent.value > 0) || (el->bytesRcvd.value > 0)) { if(el->fcCounters->hostNumFcAddress[0] != '\0') { safe_snprintf(__FILE__, __LINE__, hostKey, sizeof (hostKey), "%s-%d", el->fcCounters->hostNumFcAddress, el->fcCounters->vsanId); } else { /* For the time being do not save IP-less hosts */ unlockHostsHashMutex(el); return; } adjHostName = dotToSlash(hostKey); safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName, adjHostName); mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions); traceEventRRDebug(2, "Updating %s [%s/%d]", hostKey, el->fcCounters->hostNumFcAddress, el->fcCounters->vsanId); updateTrafficCounter(rrdPath, "pktSent", &el->pktSent, 0); updateTrafficCounter(rrdPath, "pktRcvd", &el->pktRcvd, 0); updateTrafficCounter(rrdPath, "bytesSent", &el->bytesSent, 0); updateTrafficCounter(rrdPath, "bytesRcvd", &el->bytesRcvd, 0); if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) { updateTrafficCounter(rrdPath, "fcFcpBytesSent", &el->fcCounters->fcFcpBytesSent, 0); updateTrafficCounter(rrdPath, "fcFcpBytesRcvd", &el->fcCounters->fcFcpBytesRcvd, 0); updateTrafficCounter(rrdPath, "fcFiconBytesSent", &el->fcCounters->fcFiconBytesSent, 0); updateTrafficCounter(rrdPath, "fcFiconBytesRcvd", &el->fcCounters->fcFiconBytesRcvd, 0); updateTrafficCounter(rrdPath, "fcElsBytesSent", &el->fcCounters->fcElsBytesSent, 0); updateTrafficCounter(rrdPath, "fcElsBytesRcvd", &el->fcCounters->fcElsBytesRcvd, 0); updateTrafficCounter(rrdPath, "fcDnsBytesSent", &el->fcCounters->fcDnsBytesSent, 0); updateTrafficCounter(rrdPath, "fcDnsBytesRcvd", &el->fcCounters->fcDnsBytesRcvd, 0); updateTrafficCounter(rrdPath, "fcSwilsBytesSent", &el->fcCounters->fcSwilsBytesSent, 0); updateTrafficCounter(rrdPath, "fcSwilsBytesRcvd", &el->fcCounters->fcSwilsBytesRcvd, 0); updateTrafficCounter(rrdPath, "fcIpfcBytesSent", &el->fcCounters->fcIpfcBytesSent, 0); updateTrafficCounter(rrdPath, "fcIpfcBytesRcvd", &el->fcCounters->fcIpfcBytesRcvd, 0); updateTrafficCounter(rrdPath, "otherFcBytesSent", &el->fcCounters->otherFcBytesSent, 0); updateTrafficCounter(rrdPath, "otherFcBytesRcvd", &el->fcCounters->otherFcBytesRcvd, 0); updateTrafficCounter(rrdPath, "fcRscnsRcvd", &el->fcCounters->fcRscnsRcvd, 0); updateTrafficCounter(rrdPath, "scsiReadBytes", &el->fcCounters->scsiReadBytes, 0); updateTrafficCounter(rrdPath, "scsiWriteBytes", &el->fcCounters->scsiWriteBytes, 0); updateTrafficCounter(rrdPath, "scsiOtherBytes", &el->fcCounters->scsiOtherBytes, 0); updateTrafficCounter(rrdPath, "class2Sent", &el->fcCounters->class2Sent, 0); updateTrafficCounter(rrdPath, "class2Rcvd", &el->fcCounters->class2Rcvd, 0); updateTrafficCounter(rrdPath, "class3Sent", &el->fcCounters->class3Sent, 0); updateTrafficCounter(rrdPath, "class3Rcvd", &el->fcCounters->class3Rcvd, 0); updateTrafficCounter(rrdPath, "classFSent", &el->fcCounters->classFSent, 0); updateTrafficCounter(rrdPath, "classFRcvd", &el->fcCounters->classFRcvd, 0); } if(dumpDetail == FLAG_RRD_DETAIL_HIGH) { updateCounter(rrdPath, "totContactedPeersSent", el->totContactedSentPeers, 0); updateCounter(rrdPath, "totContactedPeersRcvd", el->totContactedRcvdPeers, 0); } if(adjHostName != NULL) free(adjHostName); } unlockHostsHashMutex(el); ntop_conditional_sched_yield(); /* Allow other threads to run */ return; } /* ****************************** */ static void* rrdTrafficThreadLoop(void* notUsed _UNUSED_) { traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Throughput data collection: Thread starting [p%d]", pthread_self(), getpid()); ntopSleepUntilStateRUN(); traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Throughput data collection: Thread running [p%d]", pthread_self(), getpid()); for(;myGlobals.ntopRunState <= FLAG_NTOPSTATE_RUN;) { int devIdx; char rrdPath[512]; ntopSleepWhileSameState(dumpShortInterval); if(myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN) { traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Throughput data collection: Thread stopping [p%d] State>RUN", pthread_self(), getpid()); break; } rrdTime = time(NULL); for(devIdx=0; devIdx= FLAG_NTOPSTATE_STOPCAP) { traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Data collection thread stopping [p%d] %s", pthread_self(), getpid(), myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN ? "State>RUN" : "Plugin inactive"); break; } /* Note, if this is stopcap, we run 1 more cycle and break out at the end so we don't lose data! */ gettimeofday(&rrdStartOfCycle, NULL); numRRDUpdates = 0; numRuns++; rrdTime = time(NULL); /* ****************************************************** */ numLocalNets = 0; /* Avoids strtok to blanks into hostsFilter */ safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s", hostsFilter); handleAddressLists(rrdPath, networks, &numLocalNets, value, sizeof(value), CONST_HANDLEADDRESSLISTS_RRD); /* ****************************************************** */ if(dumpDomains) { DomainStats **stats, *tmpStats, *statsEntry; u_int maxHosts = 0; Counter totBytesSent = 0; Counter totBytesRcvd = 0; HostTraffic *el; u_short keyValue=0; for(devIdx=0; devIdxl2Family != FLAG_HOST_TRAFFIC_AF_ETH) continue; fillDomainName(el); /* if we didn't get a domain name, bail out */ if ((el->dnsDomainValue == NULL) || (el->dnsDomainValue[0] == '\0') || (el->ip2ccValue == NULL) || (el->hostResolvedName[0] == '\0') || broadcastHost(el) ) { continue; } for(keyValue=0, idx=0; el->dnsDomainValue[idx] != '\0'; idx++) keyValue += (idx+1)*(u_short)el->dnsDomainValue[idx]; keyValue %= maxHosts; while((stats[keyValue] != NULL) && (strcasecmp(stats[keyValue]->domainHost->dnsDomainValue, el->dnsDomainValue) != 0)) keyValue = (keyValue+1) % maxHosts; /* if we just start counting for this domain... */ if(stats[keyValue] != NULL) statsEntry = stats[keyValue]; else { statsEntry = &tmpStats[numEntries++]; memset(statsEntry, 0, sizeof(DomainStats)); statsEntry->domainHost = el; stats[keyValue] = statsEntry; traceEventRRDebug(2, "[%d] %s/%s", numEntries, el->dnsDomainValue, el->ip2ccValue); } /* count this host's stats in the domain stats */ totBytesSent += el->bytesSent.value; statsEntry->bytesSent.value += el->bytesSent.value; statsEntry->bytesRcvd.value += el->bytesRcvd.value; totBytesRcvd += el->bytesRcvd.value; statsEntry->tcpSent.value += el->tcpSentLoc.value + el->tcpSentRem.value; statsEntry->udpSent.value += el->udpSentLoc.value + el->udpSentRem.value; statsEntry->icmpSent.value += el->icmpSent.value; statsEntry->icmp6Sent.value += el->icmp6Sent.value; statsEntry->tcpRcvd.value += el->tcpRcvdLoc.value + el->tcpRcvdFromRem.value; statsEntry->udpRcvd.value += el->udpRcvdLoc.value + el->udpRcvdFromRem.value; statsEntry->icmpRcvd.value += el->icmpRcvd.value; statsEntry->icmp6Rcvd.value += el->icmp6Rcvd.value; if(numEntries >= maxHosts) break; } /* if we didn't find a single domain, continue with the next interface */ if (numEntries == 0) { free(tmpStats); free(stats); continue; } /* insert all domain data for this interface into the RRDs */ for (idx=0; idx < numEntries; idx++) { if(statsEntry->domainHost->dnsDomainValue != NULL) { statsEntry = &tmpStats[idx]; safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/domains/%s/", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName, statsEntry->domainHost->dnsDomainValue); mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions); traceEventRRDebug(2, "Updating %s", rrdPath); updateCounter(rrdPath, "bytesSent", statsEntry->bytesSent.value, 0); updateCounter(rrdPath, "bytesRcvd", statsEntry->bytesRcvd.value, 0); updateCounter(rrdPath, "tcpSent", statsEntry->tcpSent.value, 0); updateCounter(rrdPath, "udpSent", statsEntry->udpSent.value, 0); updateCounter(rrdPath, "icmpSent", statsEntry->icmpSent.value, 0); updateCounter(rrdPath, "icmp6Sent", statsEntry->icmp6Sent.value, 0); updateCounter(rrdPath, "tcpRcvd", statsEntry->tcpRcvd.value, 0); updateCounter(rrdPath, "udpRcvd", statsEntry->udpRcvd.value, 0); updateCounter(rrdPath, "icmpRcvd", statsEntry->icmpRcvd.value, 0); updateCounter(rrdPath, "icmp6Rcvd", statsEntry->icmp6Rcvd.value, 0); } } /* for */ free(tmpStats); free(stats); } } /* ****************************************************** */ if(dumpHosts) { for(devIdx=0; devIdxl2Family == FLAG_HOST_TRAFFIC_AF_ETH) rrdUpdateIPHostStats(el, devIdx); else if (el->l2Family == FLAG_HOST_TRAFFIC_AF_FC) rrdUpdateFcHostStats(el, devIdx); } } } /* ************************** */ if(dumpFlows) { FlowFilterList *list = myGlobals.flowsList; while(list != NULL) { if(list->pluginStatus.activePlugin) { safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/flows/%s/", myGlobals.rrdPath, list->flowName); mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions); updateCounter(rrdPath, "packets", list->packets.value, 0); updateCounter(rrdPath, "bytes", list->bytes.value, 0); } list = list->next; } } /* ************************** */ if(dumpInterfaces) { for(devIdx=0; devIdxnumNetFlowsPktsRcvd, 0); updateCounter(rrdPath, "NF_numFlows", myGlobals.device[devIdx].netflowGlobals->numNetFlowsRcvd, 0); updateCounter(rrdPath, "NF_numDiscardedFlows", myGlobals.device[devIdx].netflowGlobals->numBadFlowPkts+ myGlobals.device[devIdx].netflowGlobals->numBadFlowBytes+ myGlobals.device[devIdx].netflowGlobals->numBadFlowReality+ myGlobals.device[devIdx].netflowGlobals->numNetFlowsV9UnknTemplRcvd, 0); if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd > 0) updateGauge(rrdPath, "NF_avgTcpNewFlowSize", myGlobals.device[devIdx].netflowGlobals->totalNetFlowsTCPSize/ myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd, 0); if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd > 0) updateGauge(rrdPath, "NF_avgUdpNewFlowSize", myGlobals.device[devIdx].netflowGlobals->totalNetFlowsUDPSize/ myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd, 0); if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd > 0) updateGauge(rrdPath, "NF_avgICMPNewFlowSize", myGlobals.device[devIdx].netflowGlobals->totalNetFlowsICMPSize/ myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd, 0); if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd > 0) updateGauge(rrdPath, "NF_avgOtherFlowSize", myGlobals.device[devIdx].netflowGlobals->totalNetFlowsOtherSize/ myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd, 0); updateGauge(rrdPath, "NF_newTcpNetFlows", myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd, 0); updateGauge(rrdPath, "NF_newUdpNetFlows", myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd, 0); updateGauge(rrdPath, "NF_newIcmpNetFlows", myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd, 0); updateGauge(rrdPath, "NF_newOtherNetFlows", myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd, 0); updateGauge(rrdPath, "NF_numNetFlows", myGlobals.device[devIdx].netflowGlobals->numNetFlowsRcvd- myGlobals.device[devIdx].netflowGlobals->lastNumNetFlowsRcvd, 0); /* Update Counters */ myGlobals.device[devIdx].netflowGlobals->lastNumNetFlowsRcvd = myGlobals.device[devIdx].netflowGlobals->numNetFlowsRcvd; myGlobals.device[devIdx].netflowGlobals->totalNetFlowsTCPSize = 0; myGlobals.device[devIdx].netflowGlobals->totalNetFlowsUDPSize = 0; myGlobals.device[devIdx].netflowGlobals->totalNetFlowsICMPSize = 0; myGlobals.device[devIdx].netflowGlobals->totalNetFlowsOtherSize = 0; myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd = 0; myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd = 0; myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd = 0; myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd = 0; } if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) { updateCounter(rrdPath, "droppedPkts", myGlobals.device[devIdx].droppedPkts.value, 0); updateCounter(rrdPath, "fragmentedIpBytes", myGlobals.device[devIdx].fragmentedIpBytes.value, 0); updateCounter(rrdPath, "tcpBytes", myGlobals.device[devIdx].tcpBytes.value, 0); updateCounter(rrdPath, "udpBytes", myGlobals.device[devIdx].udpBytes.value, 0); updateCounter(rrdPath, "otherIpBytes", myGlobals.device[devIdx].otherIpBytes.value, 0); updateCounter(rrdPath, "icmpBytes", myGlobals.device[devIdx].icmpBytes.value, 0); updateCounter(rrdPath, "dlcBytes", myGlobals.device[devIdx].dlcBytes.value, 0); updateCounter(rrdPath, "ipxBytes", myGlobals.device[devIdx].ipxBytes.value, 0); updateCounter(rrdPath, "stpBytes", myGlobals.device[devIdx].stpBytes.value, 0); updateCounter(rrdPath, "decnetBytes", myGlobals.device[devIdx].decnetBytes.value, 0); updateCounter(rrdPath, "netbiosBytes", myGlobals.device[devIdx].netbiosBytes.value, 0); updateCounter(rrdPath, "arpRarpBytes", myGlobals.device[devIdx].arpRarpBytes.value, 0); updateCounter(rrdPath, "atalkBytes", myGlobals.device[devIdx].atalkBytes.value, 0); updateCounter(rrdPath, "egpBytes", myGlobals.device[devIdx].egpBytes.value, 0); updateCounter(rrdPath, "osiBytes", myGlobals.device[devIdx].osiBytes.value, 0); updateCounter(rrdPath, "ipv6Bytes", myGlobals.device[devIdx].ipv6Bytes.value, 0); updateCounter(rrdPath, "otherBytes", myGlobals.device[devIdx].otherBytes.value, 0); updateCounter(rrdPath, "upTo64Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo64.value, 0); updateCounter(rrdPath, "upTo128Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo128.value, 0); updateCounter(rrdPath, "upTo256Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo256.value, 0); updateCounter(rrdPath, "upTo512Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo512.value, 0); updateCounter(rrdPath, "upTo1024Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo1024.value, 0); updateCounter(rrdPath, "upTo1518Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo1518.value, 0); updateCounter(rrdPath, "badChecksumPkts", myGlobals.device[devIdx].rcvdPktStats.badChecksum.value, 0); updateCounter(rrdPath, "tooLongPkts", myGlobals.device[devIdx].rcvdPktStats.tooLong.value, 0); if(myGlobals.device[devIdx].ipProtosList != NULL) { protoList = myGlobals.ipProtosList, idx=0; while(protoList != NULL) { Counter c = myGlobals.device[devIdx].ipProtosList[idx].value; if(c > 0) updateCounter(rrdPath, protoList->protocolName, c, 0); idx++, protoList = protoList->next; } } } if(dumpDetail == FLAG_RRD_DETAIL_HIGH) { if(myGlobals.device[devIdx].ipProtoStats != NULL) { safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/IP_", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName); for(j=0; jtotPktsSinceLastRRDDump > AS_RRD_DUMP_PKTS_THRESHOLD) { safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath), "%s/interfaces/%s/AS/%d/", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName, asStats->as_id); mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions); updateCounter(rrdIfPath, "ifInOctets", asStats->inBytes.value, 0); updateCounter(rrdIfPath, "ifInPkts", asStats->inPkts.value, 0); updateCounter(rrdIfPath, "ifOutOctets", asStats->outBytes.value, 0); updateCounter(rrdIfPath, "ifOutPkts", asStats->outPkts.value, 0); updateCounter(rrdIfPath, "ifSelfOctets", asStats->selfBytes.value, 0); updateCounter(rrdIfPath, "ifSelfPkts", asStats->selfPkts.value, 0); } } asStats->totPktsSinceLastRRDDump = 0; asStats = asStats->next; totAS++; } releaseMutex(&myGlobals.device[devIdx].asMutex); if(dumpASs) { safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath), "%s/interfaces/%s/AS/", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName); mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions); updateGauge(rrdIfPath, "numAS", totAS, 0); // traceEvent(CONST_TRACE_WARNING, "numAS=%d", totAS); } } /* ******************************** */ if(myGlobals.device[devIdx].netflowGlobals) { InterfaceStats *ifStats; accessMutex(&myGlobals.device[devIdx].netflowGlobals->ifStatsMutex, "rrdPluginNetflow"); ifStats = myGlobals.device[devIdx].netflowGlobals->ifStats; while(ifStats != NULL) { char rrdIfPath[512]; safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath), "%s/interfaces/%s/NetFlow/%d/", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName, ifStats->interface_id); mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions); updateCounter(rrdIfPath, "ifInOctets", ifStats->inBytes.value, 0); updateCounter(rrdIfPath, "ifInPkts", ifStats->inPkts.value, 0); updateCounter(rrdIfPath, "ifOutOctets", ifStats->outBytes.value, 0); updateCounter(rrdIfPath, "ifOutPkts", ifStats->outPkts.value, 0); updateCounter(rrdIfPath, "ifSelfOctets", ifStats->selfBytes.value, 0); updateCounter(rrdIfPath, "ifSelfPkts", ifStats->selfPkts.value, 0); ifStats = ifStats->next; } releaseMutex(&myGlobals.device[devIdx].netflowGlobals->ifStatsMutex); } /* ******************************** */ if(myGlobals.device[devIdx].sflowGlobals) { IfCounters *ifName = myGlobals.device[devIdx].sflowGlobals->ifCounters; while(ifName != NULL) { char rrdIfPath[512]; safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath), "%s/interfaces/%s/sFlow/%u/", myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName, ifName->ifIndex); mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions); updateCounter(rrdIfPath, "ifInOctets", ifName->ifInOctets, 0); updateCounter(rrdIfPath, "ifInUcastPkts", ifName->ifInUcastPkts, 0); updateCounter(rrdIfPath, "ifInMulticastPkts", ifName->ifInMulticastPkts, 0); updateCounter(rrdIfPath, "ifInBroadcastPkts", ifName->ifInBroadcastPkts, 0); updateCounter(rrdIfPath, "ifInDiscards", ifName->ifInDiscards, 0); updateCounter(rrdIfPath, "ifInErrors", ifName->ifInErrors, 0); updateCounter(rrdIfPath, "ifInUnknownProtos", ifName->ifInUnknownProtos, 0); updateCounter(rrdIfPath, "ifOutOctets", ifName->ifOutOctets, 0); updateCounter(rrdIfPath, "ifOutUcastPkts", ifName->ifOutUcastPkts, 0); updateCounter(rrdIfPath, "ifOutMulticastPkts", ifName->ifOutMulticastPkts, 0); updateCounter(rrdIfPath, "ifOutBroadcastPkts", ifName->ifOutBroadcastPkts, 0); updateCounter(rrdIfPath, "ifOutDiscards", ifName->ifOutDiscards, 0); updateCounter(rrdIfPath, "ifOutErrors", ifName->ifOutErrors, 0); ifName = ifName->next; } } } } /* ************************** */ if(dumpMatrix) { int k; for(k=0; kbytesSent.value > 0) { safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/matrix/%s/%s/", myGlobals.rrdPath, myGlobals.device[k].uniqueIfName, myGlobals.device[k].ipTrafficMatrixHosts[i]->hostNumIpAddress, myGlobals.device[k].ipTrafficMatrixHosts[j]->hostNumIpAddress); mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions); updateCounter(rrdPath, "pkts", myGlobals.device[k].ipTrafficMatrix[idx]->pktsSent.value, 0); updateCounter(rrdPath, "bytes", myGlobals.device[k].ipTrafficMatrix[idx]->bytesSent.value, 0); } } } } gettimeofday(&rrdEndOfCycle, NULL); elapsed = timeval_subtract(rrdEndOfCycle, rrdStartOfCycle); #ifdef MAX_RRD_CYCLE_BUFFER rrdcycleBuffer[++rrdcycleBufferCount & (MAX_RRD_CYCLE_BUFFER - 1)] = elapsed; if(elapsed > rrdcmaxLength) rrdcmaxLength = elapsed; #endif traceEvent(CONST_TRACE_NOISY, "RRD: Cycle %lu ended, %llu RRDs updated, %.3f seconds", numRRDCycles, numRRDUpdates, elapsed); /* * If it's FLAG_NTOPSTATE_STOPCAP, and we're still running, then this * is the 1st pass. We just updated our data to save the counts, now * we kill the thread... */ if(myGlobals.ntopRunState == FLAG_NTOPSTATE_STOPCAP) { traceEvent(CONST_TRACE_WARNING, "THREADMGMT[t%lu]: RRD: STOPCAP, ending rrd thread", pthread_self()); break; } } termUdp(); rrdThread = 0; traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Data collection thread terminated [p%d]", pthread_self(), getpid()); return(0); } /* ****************************** */ static int initRRDfunct(void) { createMutex(&rrdMutex); setPluginStatus(NULL); #if 0 if (myGlobals.runningPref.rFileName != NULL) { /* Don't start RRD Plugin for capture files as it doesn't work */ traceEvent(CONST_TRACE_INFO, "RRD: plugin disabled on capture files"); active = 0; return (TRUE); /* 0 indicates success */ } #endif traceEvent(CONST_TRACE_INFO, "RRD: Welcome to the RRD plugin"); if(myGlobals.rrdPath == NULL) commonRRDinit(); createThread(&rrdThread, rrdMainLoop, NULL); traceEvent(CONST_TRACE_INFO, "THREADMGMT: RRD: Started thread (t%lu) for data collection", rrdThread); fflush(stdout); numTotalRRDUpdates = 0; return(0); } /* ****************************** */ static void termRRDfunct(u_char termNtop /* 0=term plugin, 1=term ntop */) { int count=0, rc; /* Hold until rrd is finished or 15s elapsed... */ traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Shutting down, locking mutex (may block for a little while)"); while ((count++ < 5) && (tryLockMutex(&rrdMutex, "Termination") != 0)) { sleep(3); } if(rrdMutex.isLocked) { traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Locked mutex, continuing shutdown"); } else { traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Unable to lock mutex, continuing shutdown anyway"); } if(active) { if(rrdThread) { rc = killThread(&rrdThread); if (rc == 0) traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: killThread(rrdThread) succeeded", pthread_self()); else traceEvent(CONST_TRACE_ERROR, "THREADMGMT[t%lu]: RRD: killThread(rrdThread) failed, rc %s(%d)", pthread_self(), strerror(rc), rc); } if(rrdTrafficThread) { rc = killThread(&rrdTrafficThread); if (rc == 0) traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: killThread(rrdTrafficThread) succeeded", pthread_self()); else traceEvent(CONST_TRACE_ERROR, "THREADMGMT[t%lu]: RRD: killThread(rrdTrafficThread) failed, rc %s(%d)", pthread_self(), strerror(rc), rc); } /* if((rrdThread != 0) || (rrdTrafficThread != 0)) { traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Waiting %d seconds for threads to stop", pthread_self(), (PARM_SLEEP_LIMIT + 2)); sleep(PARM_SLEEP_LIMIT + 2); } */ traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Plugin shutdown continuing", pthread_self()); } if(hostsFilter != NULL) free(hostsFilter); if(myGlobals.rrdPath != NULL) free(myGlobals.rrdPath); deleteMutex(&rrdMutex); traceEvent(CONST_TRACE_INFO, "RRD: Thanks for using the rrdPlugin"); traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Done"); fflush(stdout); initialized = 0; /* Reinit on restart */ active = 0; } /* ****************************** */ /* Plugin entry fctn */ #ifdef MAKE_STATIC_PLUGIN PluginInfo* rrdPluginEntryFctn(void) #else PluginInfo* PluginEntryFctn(void) #endif { traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Welcome to %s. (C) 2002-07 by Luca Deri.", rrdPluginInfo->pluginName); return(rrdPluginInfo); } /* ************************************************ */ /* This must be here so it can access the struct PluginInfo, above */ static void setPluginStatus(char * status) { if(rrdPluginInfo->pluginStatusMessage != NULL) free(rrdPluginInfo->pluginStatusMessage); if(status == NULL) { rrdPluginInfo->pluginStatusMessage = NULL; } else { rrdPluginInfo->pluginStatusMessage = strdup(status); } }