[re-resend] [taking this to ntop-dev as there's actual code involved now...]
> -----Original Message----- > From: Burton M. Strauss III [mailto:[EMAIL PROTECTED] > Sent: Saturday, January 24, 2004 1:01 AM > To: [EMAIL PROTECTED] > Subject: RE: [Ntop] Per host/subdomain RRD stats? > > > You probably could do it, but it would be a bit of work. > > Assuming the same definition of 'domain' as the rest of ntop > - strip the > left most qualifier, then what you need to do is basically rip out the > report routine and clone it into rrdPlugin.c That was indeed my approach also. > (remember, with > rrds you can do > only one update per time interval, so you have to accumulate > and update, not > update update update...) You mean accumulate all hosts per domain, and then do UpdateCounter right? My graphs indeed do look kinda edgy. Anyway, I created a patch to add domain RRD's. Its modifies 2 files: - report.c to add an RRD icon and link in the "Statistics for hosts in Domain %s" page - rrdPlugin.c to add the RRD code to dump domain data Almost everything seems to work, RRDs are created and data is written to the RRDs. Only there's one problem. After the rrdplugin has run on its regular interval, the Domain Stats at the IP Summary->Domain page are reset! I'm not sure what is causing this problem, but something (fillDomainName?) must be modifying data that is depended upon by printDomainStats. I attached my code and I hope someone can shed any light on this matter. Thanks, -- Robbert --- report.c.orig 2004-01-26 22:29:42.000000000 +0100 +++ report.c 2004-01-28 10:59:57.000000000 +0100 @@ -4315,6 +4315,28 @@ if(numEntries >= maxHosts) break; } /* for(;;) */ +#ifndef EMBEDDED + /* RRDs for domains */ + if (domainName != NULL) { + struct stat statbufDomain; + + /* Do NOT add a '/' at the end of the path because Win32 will complain about it */ + snprintf(buf, sizeof(buf), "%s/interfaces/%s/domains/%s", + myGlobals.rrdPath != NULL ? myGlobals.rrdPath : ".", + myGlobals.device[myGlobals.actualReportDeviceId].humanFriendlyName,domainNam e); + + if((i = stat(buf, &statbufDomain)) == 0) { + if(snprintf(buf, sizeof(buf), "<CENTER>" + "[ <A HREF=\"/plugins/rrdPlugin?action=list&key=interfaces/%s/domains/%s&title=Dom ain%%20%s\">" + "<IMG BORDER=0 SRC=/graph.gif></A> ]</CENTER>\n", + myGlobals.device[myGlobals.actualReportDeviceId].humanFriendlyName, + domainName,domainName) < 0) + BufferTooShort(); + sendString(buf); + } + } +#endif + if(numEntries == 0) { printNoDataYet(); free(tmpStats); free(stats); --- plugins/rrdPlugin.c.orig 2004-01-19 15:25:32.000000000 +0100 +++ plugins/rrdPlugin.c 2004-01-20 23:18:13.000000000 +0100 @@ -78,7 +78,7 @@ pthread_t rrdThread; #endif -static u_short dumpFlows, dumpHosts, dumpInterfaces, dumpMatrix, shownCreate=0; +static u_short dumpDomains, dumpFlows, dumpHosts, dumpInterfaces, dumpMatrix, shownCreate=0; #ifndef WIN32 static u_short dumpPermissions; #endif @@ -905,6 +905,13 @@ dumpMonths = 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; @@ -986,6 +993,7 @@ 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"); @@ -1010,7 +1018,7 @@ char buf[1024], *strtokState, *mainState, *urlPiece, rrdKey[64], rrdName[64], rrdTitle[64], startTime[32], endTime[32], rrdPrefix[32]; u_char action = FLAG_RRD_ACTION_NONE; - int _dumpFlows, _dumpHosts, _dumpInterfaces, _dumpMatrix, _dumpDetail, _dumpInterval, _dumpHours, _dumpDays, _dumpMonths; + int _dumpDomains, _dumpFlows, _dumpHosts, _dumpInterfaces, _dumpMatrix, _dumpDetail, _dumpInterval, _dumpHours, _dumpDays, _dumpMonths; char * _hostsFilter; #ifndef WIN32 int _dumpPermissions; @@ -1020,6 +1028,7 @@ commonRRDinit(); /* Initial values - remember, for checkboxes these need to be OFF (there's no html UNCHECKED option) */ + _dumpDomains=0; _dumpFlows=0; _dumpHosts=0; _dumpInterfaces=0; @@ -1122,6 +1131,8 @@ myGlobals.rrdPath = (char*)malloc(vlen); unescape(myGlobals.rrdPath, vlen, value); storePrefsValue("rrd.rrdPath", myGlobals.rrdPath); + } else if(strcmp(key, "dumpDomains") == 0) { + _dumpDomains = 1; } else if(strcmp(key, "dumpFlows") == 0) { _dumpFlows = 1; } else if(strcmp(key, "dumpDetail") == 0) { @@ -1155,6 +1166,7 @@ dumpDays = _dumpDays; dumpMonths = _dumpMonths; /* traceEvent(CONST_TRACE_INFO, "RRD: dumpFlows=%d", dumpFlows); */ + dumpDomains=_dumpDomains; dumpFlows=_dumpFlows; dumpHosts=_dumpHosts; dumpInterfaces=_dumpInterfaces; @@ -1168,6 +1180,7 @@ snprintf(buf, sizeof(buf), "%d", dumpHours); storePrefsValue("rrd.dataDumpHours", buf); snprintf(buf, sizeof(buf), "%d", dumpDays); storePrefsValue("rrd.dataDumpDays", buf); snprintf(buf, sizeof(buf), "%d", dumpMonths); storePrefsValue("rrd.dataDumpMonths", buf); + snprintf(buf, sizeof(buf), "%d", dumpDomains); storePrefsValue("rrd.dataDumpDomains", buf); snprintf(buf, sizeof(buf), "%d", dumpFlows); storePrefsValue("rrd.dataDumpFlows", buf); snprintf(buf, sizeof(buf), "%d", dumpHosts); storePrefsValue("rrd.dataDumpHosts", buf); snprintf(buf, sizeof(buf), "%d", dumpInterfaces); storePrefsValue("rrd.dataDumpInterfaces", buf); @@ -1247,6 +1260,11 @@ sendString("<TR><TH ALIGN=LEFT "DARK_BG">Data to Dump</TH><TD>"); + if(snprintf(buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpDomains VALUE=1 %s> Domains<br>\n", + dumpDomains ? "CHECKED" : "" ) < 0) + BufferTooShort(); + sendString(buf); + if(snprintf(buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpFlows VALUE=1 %s> Flows<br>\n", dumpFlows ? "CHECKED" : "" ) < 0) BufferTooShort(); @@ -1549,6 +1567,123 @@ /* ****************************************************** */ + DomainStats **stats, *tmpStats, *statsEntry; + u_int maxHosts, len = 0; + Counter totBytesSent = 0; + Counter totBytesRcvd = 0; + + if(dumpDomains) { + for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) { + + // save this as it may change + maxHosts = myGlobals.device[devIdx].hostsno; + len = sizeof(DomainStats)*maxHosts; + tmpStats = (DomainStats*)malloc(len); + memset(tmpStats, 0, len); + + len = sizeof(DomainStats**)*maxHosts; + stats = (DomainStats**)malloc(len); + memset(stats, 0, len); + + HostTraffic *el; + u_int numEntries = 0; + + // walk through all hosts, getting their domain names and counting stats + for (el = getFirstHost(devIdx); + el != NULL; el = getNextHost(devIdx, el)) { + + fillDomainName(el); + + // if we didn't get a domain name, bail out + if ((el->fullDomainName == NULL) + || (el->fullDomainName[0] == '\0') + || (el->dotDomainName == NULL) + || (el->hostSymIpAddress[0] == '\0') + || broadcastHost(el) + ) { + continue; + } + + u_short keyValue=0; + + for(keyValue=0, idx=0; el->fullDomainName[idx] != '\0'; idx++) + keyValue += (idx+1)*(u_short)el->fullDomainName[idx]; + + keyValue %= maxHosts; + + while((stats[keyValue] != NULL) + && (strcasecmp(stats[keyValue]->domainHost->fullDomainName, + el->fullDomainName) != 0)) + keyValue = (keyValue+1) % myGlobals.device[devIdx].actualHashSize; + + // 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; +#if RRD_DEBUG >= 2 + traceEvent(CONST_TRACE_INFO, "RRD_DEBUG [%d] %s/%s", numEntries, el->fullDomainName, el->dotDomainName); +#endif + } + + // 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++) { + statsEntry = &tmpStats[idx]; + + snprintf(rrdPath, sizeof(rrdPath), "%s/interfaces/%s/domains/%s/", + myGlobals.rrdPath, myGlobals.device[devIdx].humanFriendlyName, + statsEntry->domainHost->fullDomainName); + mkdir_p(rrdPath); + +#if RRD_DEBUG >= 2 + traceEvent(CONST_TRACE_INFO, "RRD: Updating %s", rrdPath); +#endif + updateCounter(rrdPath, "bytesSent", statsEntry->bytesSent.value); + updateCounter(rrdPath, "bytesRcvd", statsEntry->bytesRcvd.value); + + updateCounter(rrdPath, "tcpSent", statsEntry->tcpSent.value); + updateCounter(rrdPath, "udpSent", statsEntry->udpSent.value); + updateCounter(rrdPath, "icmpSent", statsEntry->icmpSent.value); + updateCounter(rrdPath, "icmp6Sent", statsEntry->icmp6Sent.value); + + updateCounter(rrdPath, "tcpRcvd", statsEntry->tcpRcvd.value); + updateCounter(rrdPath, "udpRcvd", statsEntry->udpRcvd.value); + updateCounter(rrdPath, "icmpRcvd", statsEntry->icmpRcvd.value); + updateCounter(rrdPath, "icmp6Rcvd", statsEntry->icmp6Rcvd.value); + } + + free(tmpStats); free(stats); + } + } + + /* ****************************************************** */ + if(dumpHosts) { for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) { for(i=1; i<myGlobals.device[devIdx].actualHashSize; i++) { _______________________________________________ Ntop-dev mailing list [EMAIL PROTECTED] http://listgateway.unipi.it/mailman/listinfo/ntop-dev
