void updateNioCounters(HSP *sp) { // don't do anything if we already refreshed the numbers less than a second ago if(sp->nio_last_update == sp->clk) { return; } sp->nio_last_update = sp->clk; // first read all the counters into new_nio PPDH_RAW_COUNTER_ITEM value; uint32_t icount = readMultiCounter("\\Network Interface(*)\\Bytes Received/sec",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ //myLog(LOG_DEBUG, "bytes_received counter <%s> = %lu", // value[i].szName, // value[i].RawValue.FirstValue); SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->bytes_in = value[i].RawValue.FirstValue; } my_free(value); value = NULL; } icount = readMultiCounter("\\Network Interface(*)\\Packets Received/sec",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->pkts_in = (uint32_t)value[i].RawValue.FirstValue; } my_free(value); value = NULL; } icount = readMultiCounter("\\Network Interface(*)\\Packets Received Errors",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->errs_in = (uint32_t)value[i].RawValue.FirstValue; } my_free(value); value = NULL; } icount = readMultiCounter("\\Network Interface(*)\\Packets Received Discarded",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->drops_in = (uint32_t)value[i].RawValue.FirstValue; } my_free(value); value = NULL; } icount = readMultiCounter("\\Network Interface(*)\\Bytes Sent/sec",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->bytes_out = value[i].RawValue.FirstValue; } my_free(value); value = NULL; } icount = readMultiCounter("\\Network Interface(*)\\Packets Sent/sec",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->pkts_out = (uint32_t)value[i].RawValue.FirstValue; } my_free(value); value = NULL; } icount = readMultiCounter("\\Network Interface(*)\\Packets Sent Errors",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->errs_out = (uint32_t)value[i].RawValue.FirstValue; } my_free(value); value = NULL; } icount = readMultiCounter("\\Network Interface(*)\\Packets Sent Discarded",&value); if(value) { for(uint32_t i = 0; i < icount; i++){ SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName); if(newctrs) newctrs->drops_out = (uint32_t)value[i].RawValue.FirstValue; } my_free(value); value = NULL; } // now compute the deltas, sanity check them, accumulate and latch for(uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) { SFLAdaptor *ad = sp->adaptorList->adaptors[i]; if(ad) { HSPAdaptorNIO *nio = (HSPAdaptorNIO *)ad->userData; if(nio) { // have to detect discontinuities here, so use a full // set of latched counters and accumulators. int accumulate = nio->last_update ? YES : NO; nio->last_update = sp->clk; uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64; SFLHost_nio_counters delta; #define NIO_COMPUTE_DELTA(field) delta.field = nio->new_nio.field - nio->last_nio.field NIO_COMPUTE_DELTA(pkts_in); NIO_COMPUTE_DELTA(errs_in); NIO_COMPUTE_DELTA(drops_in); NIO_COMPUTE_DELTA(pkts_out); NIO_COMPUTE_DELTA(errs_out); NIO_COMPUTE_DELTA(drops_out); if(sp->nio_polling_secs == 0) { // 64-bit byte counters NIO_COMPUTE_DELTA(bytes_in); NIO_COMPUTE_DELTA(bytes_out); } else { // for case where byte counters are 32-bit, we need // to use 32-bit unsigned arithmetic to avoid spikes delta.bytes_in = (uint32_t)nio->new_nio.bytes_in - nio->last_bytes_in32; delta.bytes_out = (uint32_t)nio->new_nio.bytes_out - nio->last_bytes_out32; nio->last_bytes_in32 = (uint32_t)nio->new_nio.bytes_in; nio->last_bytes_out32 = (uint32_t)nio->new_nio.bytes_out; maxDeltaBytes = HSP_MAX_NIO_DELTA32; // if we detect that the OS is using 64-bits then we can turn off the faster // NIO polling. This should probably be done based on the kernel version or some // other include-file definition, but it's not expensive to do it here like this: if(nio->new_nio.bytes_in > 0xFFFFFFFF || nio->new_nio.bytes_out > 0xFFFFFFFF) { myLog(LOG_DEBUG, "detected 64-bit network counters"); sp->nio_polling_secs = 0; } } if(accumulate) { // sanity check in case the counters were reset under out feet. // normally we leave this to the upstream collector, but these // numbers might be getting passed through from the hardware(?) // so we treat them with particular distrust. if(delta.bytes_in > maxDeltaBytes || delta.bytes_out > maxDeltaBytes || delta.pkts_in > HSP_MAX_NIO_DELTA32 || delta.pkts_out > HSP_MAX_NIO_DELTA32) { myLog(LOG_ERR, "detected NIO counter discontinuity"); accumulate = NO; } } if(accumulate) { #define NIO_ACCUMULATE(field) nio->nio.field += delta.field NIO_ACCUMULATE(bytes_in); NIO_ACCUMULATE(pkts_in); NIO_ACCUMULATE(errs_in); NIO_ACCUMULATE(drops_in); NIO_ACCUMULATE(bytes_out); NIO_ACCUMULATE(pkts_out); NIO_ACCUMULATE(errs_out); NIO_ACCUMULATE(drops_out); //myLog(LOG_DEBUG, "accumulated NIO counters (new=%lu old=%lu delta=%lu nio->nio.bytes_in now = %lu)", // nio->new_nio.bytes_in, nio->last_nio.bytes_in, delta.bytes_in, nio->nio.bytes_in); } #define NIO_LATCH(field) nio->last_nio.field = nio->new_nio.field NIO_LATCH(bytes_in); NIO_LATCH(pkts_in); NIO_LATCH(errs_in); NIO_LATCH(drops_in); NIO_LATCH(bytes_out); NIO_LATCH(pkts_out); NIO_LATCH(errs_out); NIO_LATCH(drops_out); } } } }
void updateNioCounters(HSP *sp) { // don't do anything if we already refreshed the numbers less than a second ago if(sp->adaptorNIOList.last_update == sp->clk) { return; } sp->adaptorNIOList.last_update = sp->clk; static int mib[] = { CTL_NET, PF_ROUTE, 0, 0, /* address family */ NET_RT_IFLIST, 0 }; /* ifIndex */ size_t needed = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { myLog(LOG_ERR, "sysctl for interface list failed"); return; } char *buf = my_calloc(needed); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { myLog(LOG_ERR, "sysctl for interface list failed (2nd time)"); } else { char *lim = buf + needed; char *next = buf; while (next < lim) { struct if_msghdr *ifm = (struct if_msghdr *)next; if (ifm->ifm_type != RTM_IFINFO) { myLog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"); break; } next += ifm->ifm_msglen; while (next < lim) { struct if_msghdr *nextifm = (struct if_msghdr *)next; if (nextifm->ifm_type != RTM_NEWADDR) break; next += nextifm->ifm_msglen; } if (!(ifm->ifm_flags & IFF_LOOPBACK) && (ifm->ifm_flags & IFF_UP)) { char deviceName[IFNAMSIZ]; uint32_t index = ifm->ifm_index; if(if_indextoname(index, deviceName)) { char *str = deviceName; trimWhitespace(str); HSPAdaptorNIO *adaptor = getAdaptorNIO(&sp->adaptorNIOList, str); if(adaptor) { uint64_t bytes_in = ifm->ifm_data.ifi_ibytes; uint64_t pkts_in = ifm->ifm_data.ifi_ipackets; uint64_t errs_in = ifm->ifm_data.ifi_ierrors; uint64_t drops_in = ifm->ifm_data.ifi_iqdrops; uint64_t bytes_out = ifm->ifm_data.ifi_obytes; uint64_t pkts_out = ifm->ifm_data.ifi_opackets; uint64_t errs_out = ifm->ifm_data.ifi_oerrors; uint64_t drops_out = (uint64_t)-1; /* unsupported */ // have to detect discontinuities here, so use a full // set of latched counters and accumulators. int accumulate = adaptor->last_update ? YES : NO; adaptor->last_update = sp->clk; uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64; SFLHost_nio_counters delta; #define NIO_COMPUTE_DELTA(field) delta.field = field - adaptor->last_nio.field NIO_COMPUTE_DELTA(pkts_in); NIO_COMPUTE_DELTA(errs_in); NIO_COMPUTE_DELTA(drops_in); NIO_COMPUTE_DELTA(pkts_out); NIO_COMPUTE_DELTA(errs_out); NIO_COMPUTE_DELTA(drops_out); if(sp->adaptorNIOList.polling_secs == 0) { // 64-bit byte counters NIO_COMPUTE_DELTA(bytes_in); NIO_COMPUTE_DELTA(bytes_out); } else { // for case where byte counters are 32-bit, we need // to use 32-bit unsigned arithmetic to avoid spikes delta.bytes_in = (uint32_t)bytes_in - adaptor->last_bytes_in32; delta.bytes_out = (uint32_t)bytes_out - adaptor->last_bytes_out32; adaptor->last_bytes_in32 = bytes_in; adaptor->last_bytes_out32 = bytes_out; maxDeltaBytes = HSP_MAX_NIO_DELTA32; // if we detect that the OS is using 64-bits then we can turn off the faster // NIO polling. This should probably be done based on the kernel version or some // other include-file definition, but it's not expensive to do it here like this: if(bytes_in > 0xFFFFFFFF || bytes_out > 0xFFFFFFFF) { myLog(LOG_INFO, "detected 64-bit counters in /proc/net/dev"); sp->adaptorNIOList.polling_secs = 0; } } if(accumulate) { // sanity check in case the counters were reset under out feet. // normally we leave this to the upstream collector, but these // numbers might be getting passed through from the hardware(?) // so we treat them with particular distrust. if(delta.bytes_in > maxDeltaBytes || delta.bytes_out > maxDeltaBytes || delta.pkts_in > HSP_MAX_NIO_DELTA32 || delta.pkts_out > HSP_MAX_NIO_DELTA32) { myLog(LOG_ERR, "detected counter discontinuity in /proc/net/dev"); accumulate = NO; } } if(accumulate) { #define NIO_ACCUMULATE(field) adaptor->nio.field += delta.field NIO_ACCUMULATE(bytes_in); NIO_ACCUMULATE(pkts_in); NIO_ACCUMULATE(errs_in); NIO_ACCUMULATE(drops_in); NIO_ACCUMULATE(bytes_out); NIO_ACCUMULATE(pkts_out); NIO_ACCUMULATE(errs_out); NIO_ACCUMULATE(drops_out); } #define NIO_LATCH(field) adaptor->last_nio.field = field NIO_LATCH(bytes_in); NIO_LATCH(pkts_in); NIO_LATCH(errs_in); NIO_LATCH(drops_in); NIO_LATCH(bytes_out); NIO_LATCH(pkts_out); NIO_LATCH(errs_out); NIO_LATCH(drops_out); } } } } } my_free(buf); }
void updateNioCounters(HSP *sp) { // don't do anything if we already refreshed the numbers less than a second ago if(sp->nio_last_update == sp->clk) { return; } sp->nio_last_update = sp->clk; FILE *procFile; procFile= fopen("/proc/net/dev", "r"); if(procFile) { #ifdef HSP_ETHTOOL_STATS int fd = socket (PF_INET, SOCK_DGRAM, 0); struct ifreq ifr; memset (&ifr, 0, sizeof(ifr)); #endif // ASCII numbers in /proc/diskstats may be 64-bit (if not now // then someday), so it seems safer to read into // 64-bit ints with scanf first, then copy them // into the host_nio structure from there. uint64_t bytes_in = 0; uint64_t pkts_in = 0; uint64_t errs_in = 0; uint64_t drops_in = 0; uint64_t bytes_out = 0; uint64_t pkts_out = 0; uint64_t errs_out = 0; uint64_t drops_out = 0; // limit the number of chars we will read from each line // (there can be more than this - fgets will chop for us) #define MAX_PROC_LINE_CHARS 240 char line[MAX_PROC_LINE_CHARS]; while(fgets(line, MAX_PROC_LINE_CHARS, procFile)) { char deviceName[MAX_PROC_LINE_CHARS]; // assume the format is: // Inter-| Receive | Transmit // face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed if(sscanf(line, "%[^:]:%"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %*u %*u %*u %*u %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64"", deviceName, &bytes_in, &pkts_in, &errs_in, &drops_in, &bytes_out, &pkts_out, &errs_out, &drops_out) == 9) { SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, trimWhitespace(deviceName)); if(adaptor && adaptor->userData) { HSPAdaptorNIO *niostate = (HSPAdaptorNIO *)adaptor->userData; #ifdef HSP_ETHTOOL_STATS HSP_ethtool_counters et_ctrs = { 0 }, et_delta = { 0 }; if (niostate->et_nfound) { // get the latest stats block for this device via ethtool // and read out the counters that we located by name. uint32_t bytes = sizeof(struct ethtool_stats); bytes += niostate->et_nctrs * sizeof(uint64_t); bytes += 32; // pad - just in case driver wants to write more struct ethtool_stats *et_stats = (struct ethtool_stats *)my_calloc(bytes); et_stats->cmd = ETHTOOL_GSTATS; et_stats->n_stats = niostate->et_nctrs; // now issue the ioctl strncpy(ifr.ifr_name, adaptor->deviceName, sizeof(ifr.ifr_name)); ifr.ifr_data = (char *)et_stats; if(ioctl(fd, SIOCETHTOOL, &ifr) >= 0) { if(debug > 2) { for(int xx = 0; xx < et_stats->n_stats; xx++) { myLog(LOG_INFO, "ethtool counter for %s at index %d == %"PRIu64, adaptor->deviceName, xx, et_stats->data[xx]); } } if(niostate->et_idx_mcasts_in) { et_ctrs.mcasts_in = et_stats->data[niostate->et_idx_mcasts_in - 1]; et_delta.mcasts_in = et_ctrs.mcasts_in - niostate->et_last.mcasts_in; } if(niostate->et_idx_mcasts_out) { et_ctrs.mcasts_out = et_stats->data[niostate->et_idx_mcasts_out - 1]; et_delta.mcasts_out = et_ctrs.mcasts_out - niostate->et_last.mcasts_out; } if(niostate->et_idx_bcasts_in) { et_ctrs.bcasts_in = et_stats->data[niostate->et_idx_bcasts_in - 1]; et_delta.bcasts_in = et_ctrs.bcasts_in - niostate->et_last.bcasts_in; } if(niostate->et_idx_bcasts_out) { et_ctrs.bcasts_out = et_stats->data[niostate->et_idx_bcasts_out - 1]; et_delta.bcasts_out = et_ctrs.bcasts_out - niostate->et_last.bcasts_out; } } my_free(et_stats); } #endif // have to detect discontinuities here, so use a full // set of latched counters and accumulators. int accumulate = niostate->last_update ? YES : NO; niostate->last_update = sp->clk; uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64; SFLHost_nio_counters delta; #define NIO_COMPUTE_DELTA(field) delta.field = field - niostate->last_nio.field NIO_COMPUTE_DELTA(pkts_in); NIO_COMPUTE_DELTA(errs_in); NIO_COMPUTE_DELTA(drops_in); NIO_COMPUTE_DELTA(pkts_out); NIO_COMPUTE_DELTA(errs_out); NIO_COMPUTE_DELTA(drops_out); if(sp->nio_polling_secs == 0) { // 64-bit byte counters NIO_COMPUTE_DELTA(bytes_in); NIO_COMPUTE_DELTA(bytes_out); } else { // for case where byte counters are 32-bit, we need // to use 32-bit unsigned arithmetic to avoid spikes delta.bytes_in = (uint32_t)bytes_in - niostate->last_bytes_in32; delta.bytes_out = (uint32_t)bytes_out - niostate->last_bytes_out32; niostate->last_bytes_in32 = bytes_in; niostate->last_bytes_out32 = bytes_out; maxDeltaBytes = HSP_MAX_NIO_DELTA32; // if we detect that the OS is using 64-bits then we can turn off the faster // NIO polling. This should probably be done based on the kernel version or some // other include-file definition, but it's not expensive to do it here like this: if(bytes_in > 0xFFFFFFFF || bytes_out > 0xFFFFFFFF) { myLog(LOG_INFO, "detected 64-bit counters in /proc/net/dev"); sp->nio_polling_secs = 0; } } if(accumulate) { // sanity check in case the counters were reset under out feet. // normally we leave this to the upstream collector, but these // numbers might be getting passed through from the hardware(?) // so we treat them with particular distrust. if(delta.bytes_in > maxDeltaBytes || delta.bytes_out > maxDeltaBytes || delta.pkts_in > HSP_MAX_NIO_DELTA32 || delta.pkts_out > HSP_MAX_NIO_DELTA32) { myLog(LOG_ERR, "detected counter discontinuity in /proc/net/dev for %s: deltaBytes=%"PRIu64",%"PRIu64" deltaPkts=%u,%u", adaptor->deviceName, delta.bytes_in, delta.bytes_out, delta.pkts_in, delta.pkts_out); accumulate = NO; } #ifdef HSP_ETHTOOL_STATS if(et_delta.mcasts_in > HSP_MAX_NIO_DELTA64 || et_delta.mcasts_out > HSP_MAX_NIO_DELTA64 || et_delta.bcasts_in > HSP_MAX_NIO_DELTA64 || et_delta.bcasts_out > HSP_MAX_NIO_DELTA64) { myLog(LOG_ERR, "detected counter discontinuity in ethtool stats"); accumulate = NO; } #endif } if(accumulate) { #define NIO_ACCUMULATE(field) niostate->nio.field += delta.field NIO_ACCUMULATE(bytes_in); NIO_ACCUMULATE(pkts_in); NIO_ACCUMULATE(errs_in); NIO_ACCUMULATE(drops_in); NIO_ACCUMULATE(bytes_out); NIO_ACCUMULATE(pkts_out); NIO_ACCUMULATE(errs_out); NIO_ACCUMULATE(drops_out); #ifdef HSP_ETHTOOL_STATS #define ET_ACCUMULATE(field) niostate->et_total.field += et_delta.field ET_ACCUMULATE(mcasts_in); ET_ACCUMULATE(mcasts_out); ET_ACCUMULATE(bcasts_in); ET_ACCUMULATE(bcasts_out); #endif } #define NIO_LATCH(field) niostate->last_nio.field = field NIO_LATCH(bytes_in); NIO_LATCH(pkts_in); NIO_LATCH(errs_in); NIO_LATCH(drops_in); NIO_LATCH(bytes_out); NIO_LATCH(pkts_out); NIO_LATCH(errs_out); NIO_LATCH(drops_out); #ifdef HSP_ETHTOOL_STATS niostate->et_last = et_ctrs; // struct copy #endif } } } #ifdef HSP_ETHTOOL_STATS if(fd >= 0) close(fd); #endif fclose(procFile); } }
/** * Updates the cached NIO counters using PDH if the counters were updated * more than a second ago. * Computes the delta between current and last counters, checks for * discontinuities (including determining whether 32 bit counters are being * use - eg for bytes - and have wrapped), accumulates totals, and stores * the latest counter values for delta computation on next invokation. * If 64 bit counters are detected, indicates this by setting * sp->nio->polling_seconds = 0 so that more * frequent polling of counters can be turned off. */ void updateNioCounters(HSP *sp) { // don't do anything if we refreshed the numbers less than a second ago if (sp->nio_last_update == sp->clk) { return; } sp->nio_last_update = sp->clk; // first read all the counters into new_nio if (query == NULL) { PDH_STATUS status = createCounterQuery(); if (status != ERROR_SUCCESS) { query = NULL; myLog(LOG_ERR, "updateNioCounters: creating query failed: 0x%x", status); return; } } PdhCollectQueryData(query); PPDH_RAW_COUNTER_ITEM_W values; uint32_t icount = 0; icount = getRawCounterValues(&bytesIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->bytes_in = values[i].RawValue.FirstValue; //myLog(LOG_INFO, "updateNioCounters: adapter=%S bytesIn=%lu", // values[i].szName, newctrs->bytes_in); } } my_free(values); icount = 0; } icount = getRawCounterValues(&pktsIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if(newctrs != NULL) { newctrs->pkts_in = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&errorsIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if(newctrs != NULL) { newctrs->errs_in = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&discardsIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->drops_in = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&bytesOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->bytes_out = values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&pktsOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->pkts_out = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&errorsOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->errs_out = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&discardsOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->drops_out = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } // now compute the deltas, sanity check them, accumulate and latch for (uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) { SFLAdaptor *ad = sp->adaptorList->adaptors[i]; if (ad != NULL) { HSPAdaptorNIO *nio = (HSPAdaptorNIO *)ad->userData; if (nio != NULL) { // have to detect discontinuities here, so use a full // set of latched counters and accumulators. BOOL accumulate = nio->last_update ? TRUE : FALSE; nio->last_update = sp->clk; uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64; SFLHost_nio_counters delta; #define NIO_COMPUTE_DELTA(field) delta.field = nio->new_nio.field - nio->last_nio.field NIO_COMPUTE_DELTA(pkts_in); NIO_COMPUTE_DELTA(errs_in); NIO_COMPUTE_DELTA(drops_in); NIO_COMPUTE_DELTA(pkts_out); NIO_COMPUTE_DELTA(errs_out); NIO_COMPUTE_DELTA(drops_out); if (sp->nio_polling_secs == 0) { // 64-bit byte counters NIO_COMPUTE_DELTA(bytes_in); NIO_COMPUTE_DELTA(bytes_out); } else { // for case where byte counters are 32-bit, we need // to use 32-bit unsigned arithmetic to avoid spikes delta.bytes_in = (uint32_t)nio->new_nio.bytes_in - nio->last_bytes_in32; delta.bytes_out = (uint32_t)nio->new_nio.bytes_out - nio->last_bytes_out32; nio->last_bytes_in32 = (uint32_t)nio->new_nio.bytes_in; nio->last_bytes_out32 = (uint32_t)nio->new_nio.bytes_out; maxDeltaBytes = HSP_MAX_NIO_DELTA32; // if we detect that the OS is using 64-bits then we can turn off the faster // NIO polling. This should probably be done based on the kernel version or some // other include-file definition, but it's not expensive to do it here like this: if (nio->new_nio.bytes_in > 0xFFFFFFFF || nio->new_nio.bytes_out > 0xFFFFFFFF) { myLog(LOG_INFO, "detected 64-bit network counters"); sp->nio_polling_secs = 0; } } if (accumulate) { // sanity check in case the counters were reset under out feet. // normally we leave this to the upstream collector, but these // numbers might be getting passed through from the hardware(?) // so we treat them with particular distrust. if (delta.bytes_in > maxDeltaBytes || delta.bytes_out > maxDeltaBytes || delta.pkts_in > HSP_MAX_NIO_DELTA32 || delta.pkts_out > HSP_MAX_NIO_DELTA32) { myLog(LOG_INFO, "detected NIO counter discontinuity"); accumulate = FALSE; } } if (accumulate) { #define NIO_ACCUMULATE(field) nio->nio.field += delta.field NIO_ACCUMULATE(bytes_in); NIO_ACCUMULATE(pkts_in); NIO_ACCUMULATE(errs_in); NIO_ACCUMULATE(drops_in); NIO_ACCUMULATE(bytes_out); NIO_ACCUMULATE(pkts_out); NIO_ACCUMULATE(errs_out); NIO_ACCUMULATE(drops_out); //myLog(LOG_INFO, "accumulated NIO counters (new=%lu old=%lu delta=%lu nio->nio.bytes_in now = %lu)", // nio->new_nio.bytes_in, nio->last_nio.bytes_in, delta.bytes_in, nio->nio.bytes_in); } #define NIO_LATCH(field) nio->last_nio.field = nio->new_nio.field NIO_LATCH(bytes_in); NIO_LATCH(pkts_in); NIO_LATCH(errs_in); NIO_LATCH(drops_in); NIO_LATCH(bytes_out); NIO_LATCH(pkts_out); NIO_LATCH(errs_out); NIO_LATCH(drops_out); } } } }