/** * Populates nio with the counters accumulated for all of the non-virtual * adaptors, first ensuring that the accumulated counters are current. * Returns TRUE if there are adaptors for which their are counters 0, * FALSE otherwise. */ BOOL readNioCounters(HSP *sp, SFLHost_nio_counters *nio) { // may need to schedule intermediate calls to updateNioCounters() // too (to avoid undetected wraps), but at the very least we need to do // it here to make sure the data is up to the second. updateNioCounters(sp); BOOL gotData = FALSE; // just add up all the counters for the non-virtual adaptors for (uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) { SFLAdaptor *ad = sp->adaptorList->adaptors[i]; if (ad != NULL) { HSPAdaptorNIO *ctrs = (HSPAdaptorNIO *)ad->userData; if (ctrs != NULL && !ctrs->isVirtual) { gotData = TRUE; myLog(LOG_INFO, "readNioCounters: accumulating: pkts_in=%lu (device=%S virtual=%d)", ctrs->nio.pkts_in, ctrs->countersInstance, ctrs->isVirtual); nio->bytes_in += ctrs->nio.bytes_in; nio->pkts_in += ctrs->nio.pkts_in; nio->errs_in += ctrs->nio.errs_in; nio->drops_in += ctrs->nio.drops_in; nio->bytes_out += ctrs->nio.bytes_out; nio->pkts_out += ctrs->nio.pkts_out; nio->errs_out += ctrs->nio.errs_out; nio->drops_out += ctrs->nio.drops_out; } } } myLog(LOG_INFO,"readNioCounters: %lu adaptors\n\trbytes:\t%llu\n\trpkts:\t%lu\n\trdrops:\t%lu\n\trerrs:\t%lu\n\ttbytes:\t%llu\n\ttpkts:\t%lu\n\ttdrops:\t%lu\n\tterrs:\t%lu\n", sp->adaptorList->num_adaptors,nio->bytes_in,nio->pkts_in,nio->drops_in,nio->errs_in,nio->bytes_out,nio->pkts_out,nio->drops_out,nio->errs_out); return gotData; }
static void openXenHandles(HSP *sp) { // need to do this while we still have root privileges if(sp->xc_handle == 0) { sp->xc_handle = xc_interface_open(); if(sp->xc_handle <= 0) { myLog(LOG_ERR, "xc_interface_open() failed : %s", strerror(errno)); } else { sp->xs_handle = xs_daemon_open_readonly(); if(sp->xs_handle == NULL) { myLog(LOG_ERR, "xs_daemon_open_readonly() failed : %s", strerror(errno)); } // get the page size [ref xenstat.c] #if defined(PAGESIZE) sp->page_size = PAGESIZE; #elif defined(PAGE_SIZE) sp->page_size = PAGE_SIZE; #else sp->page_size = sysconf(_SC_PAGE_SIZE); if(pgsiz < 0) { myLog(LOG_ERR, "Failed to retrieve page size : %s", strerror(errno)); abort(); } #endif } } }
int readMemoryCounters(SFLHost_mem_counters *mem) { int gotData = NO; MEMORYSTATUSEX memStat; memStat.dwLength = sizeof(memStat); if(GlobalMemoryStatusEx(&memStat) == 0){ myLog(LOG_ERR,"GlobalMemoryStatusEx failed: %d\n",GetLastError()); return NO; } mem->mem_total = memStat.ullTotalPhys; mem->mem_free = memStat.ullAvailPhys; mem->swap_total = memStat.ullTotalPageFile; mem->swap_free = memStat.ullAvailPageFile; mem->mem_cached = readSingleCounter("\\Memory\\Cache Bytes"); mem->swap_in = (uint32_t)readSingleCounter("\\Memory\\Pages Input/sec"); mem->swap_out = (uint32_t)readSingleCounter("\\Memory\\Pages Output/sec"); //There are no obvious Windows equivalents mem->mem_buffers = UNKNOWN_COUNTER_64; mem->mem_shared = UNKNOWN_COUNTER_64; mem->page_in = UNKNOWN_COUNTER; mem->page_out = UNKNOWN_COUNTER; gotData = YES; myLog(LOG_INFO,"readMemoryCounters:\n\ttotal: %I64d\n\tfree: %I64d\n\tcached: %I64d\n\tswap_in: %d\n\tswap_out: %d\n", mem->mem_total,mem->mem_free,mem->mem_cached,mem->swap_in,mem->swap_out); return gotData; }
/** * Runs the DNS-SD sequence to discover the sFlow server settings, * collector addresses and ports and sampling rates and polling interval * settings. * The DNS query is scoped to query for entries in the domain (zone) * configured as the domain override in the registry (if set), or the * primary domain name configured on the system if there is no domain * override. * Note that the DNS query could fail or return no results if we are * unable to discover the primary domain of the system. * HSP *sp used to update the min TTL for DNS entries so that the * next DNS request can be scheduled. * HSPSFlowSettings *settings in which sFlow collector addresses and ports * and sampling and polling settings will be populated. * Returns the number of sFlow collectors discovered or -1 on failure. */ int dnsSD(HSP *sp, HSPSFlowSettings *settings) { char request[HSP_MAX_DNS_LEN]; if (sp->DNSSD_domain) { sprintf_s(request, HSP_MAX_DNS_LEN, "%s%s", SFLOW_DNS_SD, sp->DNSSD_domain); } else { char domain[MAX_HOSTNAME_LEN]; memset(domain, 0, MAX_HOSTNAME_LEN); DWORD len = MAX_HOSTNAME_LEN; char *dot = ""; if (GetComputerNameEx(ComputerNameDnsDomain, domain, &len) == 0) { DWORD err = GetLastError(); logErr(LOG_ERR, err, "dnsSD: cannot determined DNS domain for this computer error=%u", err); } else if (len == 0) { myLog(LOG_ERR, "dnsSD: DNS domain for this computer not set"); } else { dot = "."; } sprintf_s(request, HSP_MAX_DNS_LEN, "%s%s%s", SFLOW_DNS_SD, dot, domain); } myLog(LOG_INFO, "dnsSD: request=%s", request); int num_servers = dnsSD_Request(sp, settings, request, DNS_TYPE_SRV); dnsSD_Request(sp, settings, request, DNS_TYPE_TEXT); // it's ok even if only the SRV request succeeded return num_servers; // -1 on error }
/* Use this function for debugging purpose */ void printAdjList(AdjList *pstAdjList) { int i; AdjList *pstTmpList = NULL_PTR, *pstTmpList2 = NULL_PTR; if (NULL_PTR == pstAdjList) { myLog(ERROR, "Invalid Input!"); return; } myLog(DEBUG, "Printing Adjacency List:"); pstTmpList = pstAdjList; for (i = 0; i < gNoOfVertex; i++) { pstTmpList2 = pstTmpList; while (pstTmpList2) { printf("(%d, %d) = %d\n", pstTmpList->vertexNum, pstTmpList2->vertexNum, pstTmpList2->distance); pstTmpList2 = pstTmpList2->next; } pstTmpList++; } }
/** * Initialises the sFlow filter device for receiving packet samples. */ void openFilter(HSP *sp) { sp->filter.dev = INVALID_HANDLE_VALUE; // Open the device sp->filter.dev = CreateFileW(SFLOW_FILTER_DEVICE, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (sp->filter.dev == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND) { myLog(LOG_ERR, "openFilter: sFlow Hyper-V switch extension not found (Windows Server 2012 Hyper-V not running or sFlow extension not installed). Monitoring host performance only"); } else { myLog(LOG_ERR, "openFilter: could not open device file %S: %ld. Monitoring host performance only.", SFLOW_FILTER_DEVICE, error); } } else { myLog(debug, "openFilter: attached to sFlow Hyper-V Switch extension"); //Create the ioctl overlaps for communication with the device sp->filter.ioctlOverlap.Internal = 0; sp->filter.ioctlOverlap.InternalHigh = 0; sp->filter.ioctlOverlap.Pointer = NULL; sp->filter.ioctlOverlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); createOverlaps(sp); if (queueReads(sp) != 0) { CloseHandle(sp->filter.dev); sp->filter.dev = INVALID_HANDLE_VALUE; myLog(LOG_ERR, "openFilter: could not queue initial read requests"); } else { setFilterSamplingParams(sp); } } }
/*________________---------------------------__________________ ________________ readVLAN __________________ ----------------___________________________------------------ Rejected this way of looking up the VLAN because is was not portable back to Linux 2.4 kernels, and because the /proc/net/vlan approach seemed more stable and portable. */ int32_t readVLAN(char *devName, int fd) { // check in case it is just a sub-interface with a VLAN tag // that we should ignore to avoid double-counting. We'll still // allow it through in case we are doing ULOG sampling and we // want to record flows/counters against this interface. int32_t vlan = HSP_VLAN_ALL; // for some reason if_vlan.h has only 24 characters set aside // for the device name, and no #define to capture that (like // IFNAMSIZ above) #define HSP_VLAN_IFNAMSIZ 24 if(my_strlen(devName) < HSP_VLAN_IFNAMSIZ) { struct vlan_ioctl_args vlargs; vlargs.cmd = GET_VLAN_VID_CMD; strcpy(vlargs.device1, devName); if(ioctl(fd, SIOCGIFVLAN, &vlargs) != 0) { if(debug) { myLog(LOG_ERR, "device %s Get SIOCGIFVLAN failed : %s", devName, strerror(errno)); } } else { vlan = vlargs.u.VID; if(debug) { myLog(LOG_INFO, "device %s is vlan interface for vlan %u", devName, vlan); } } } return vlan; }
int readMacAddress(char *devName, u_char *buf, int bufLen) { // we can only call dlpi_open() with root privileges. So only try to get // the MAC address if we are still root. We could cache the dlpi handle // for each interface as another field in the adaptorNIO structure, but in // practice it seems unlikely that the MAC address will change without // a reboot of the host, so it's OK to only read it at the start. If a // new interface somehow appears then it will just be instantiated without // a MAC. if(getuid() != 0) { return NO; } int macaddrlen = DLPI_PHYSADDR_MAX; int copied = 0; char macaddr[DLPI_PHYSADDR_MAX]; dlpi_handle_t dh; if (DLPI_SUCCESS != dlpi_open(devName, &dh, 0)) { myLog(LOG_ERR, "device %s dlpi_open failed : %s", devName, strerror(errno)); return 0; } // opened OK if (DLPI_SUCCESS != dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, macaddr, &macaddrlen)) { myLog(LOG_ERR, "device %s dlpi_get_physaddr failed :%s", devName, strerror(errno)); } if(macaddrlen <= bufLen) { memcpy(buf, macaddr, macaddrlen); copied = macaddrlen; } dlpi_close(dh); return copied; }
static int xenstat_dsk(HSP *sp, uint32_t dom_id, SFLHost_vrt_dsk_counters *dsk) { // [ref xenstat_linux.c] #define SYSFS_VBD_PATH "/sys/devices/xen-backend/" DIR *sysfsvbd = opendir(SYSFS_VBD_PATH); if(sysfsvbd == NULL) { myLog(LOG_ERR, "opendir %s failed : %s", SYSFS_VBD_PATH, strerror(errno)); return NO; } char scratch[sizeof(struct dirent) + _POSIX_PATH_MAX]; struct dirent *dp = NULL; for(;;) { readdir_r(sysfsvbd, (struct dirent *)scratch, &dp); if(dp == NULL) break; uint32_t vbd_dom_id; uint32_t vbd_dev; char vbd_type[256]; if(sscanf(dp->d_name, "%3s-%u-%u", vbd_type, &vbd_dom_id, &vbd_dev) == 3) { if(vbd_dom_id == dom_id) { //dsk->capacity $$$ //dsk->allocation $$$ //dsk->available $$$ if(debug > 1) myLog(LOG_INFO, "reading VBD %s for dom_id %u", dp->d_name, dom_id); dsk->rd_req += xen_vbd_counter(vbd_type, dom_id, vbd_dev, "rd_req"); dsk->rd_bytes += (xen_vbd_counter(vbd_type, dom_id, vbd_dev, "rd_sect") * HSP_SECTOR_BYTES); dsk->wr_req += xen_vbd_counter(vbd_type, dom_id, vbd_dev, "wr_req"); dsk->wr_bytes += (xen_vbd_counter(vbd_type, dom_id, vbd_dev, "wr_sect") * HSP_SECTOR_BYTES); dsk->errs += xen_vbd_counter(vbd_type, dom_id, vbd_dev, "oo_req"); } } } closedir(sysfsvbd); return YES; }
/** * Issues the DNS request to discover the sFlow service settings * (collector addresses and ports, sampling rates and polling intervals). * The DNS request is configured to bypass the DNS cache and go straight * to the wire to avoid using stale entries. * If the request succeeds, updates the min TTL in HSP *sp, parses the response, * and returns the number of records returned, populating HSPSFlowSettings *settings * with the parsed result. * If the request fails, returns -1. * char *dname contains the DNS query (fully qualified) * WORD dtype the DNS query type (SRV for collectors or TEXT for sampling rates * and polling intervals) * Note that we are using the DnsQuery function to make the DNS request. * This function does not take into account the system DNS search path, so the * DNS query must be fully qualified (ie include the domain to search). */ static int dnsSD_Request(HSP *sp, HSPSFlowSettings *settings, char *dname, WORD rtype) { PDNS_RECORD pDnsRecord; DNS_FREE_TYPE dnsFreeType; dnsFreeType = DnsFreeRecordListDeep; DNS_STATUS status = DnsQuery(dname, rtype, DNS_QUERY_WIRE_ONLY, NULL, &pDnsRecord, NULL); if (status) { //fail logErr(LOG_ERR, status, "dnsSD_Request: DNSQuery(%s, %u) failed error=%u", dname, rtype, status); return -1; } else { //process results and free int answerCount = 0; PDNS_RECORD nextRecord = pDnsRecord; while (nextRecord != NULL) { //update the minimum ttl DWORD ttl = nextRecord->dwTtl; if (sp->DNSSD_ttl == 0 || ttl < sp->DNSSD_ttl) { sp->DNSSD_ttl = ttl; } switch(rtype) { case DNS_TYPE_TEXT: if (nextRecord->wType == DNS_TYPE_TEXT) { answerCount++; DWORD stringCount = nextRecord->Data.TXT.dwStringCount; for (DWORD i = 0; i < stringCount; i++) { if (LOG_INFO <= debug) { myLog(LOG_INFO, "dnsDS_Request: DNS_TYPE_TEXT %s", nextRecord->Data.TXT.pStringArray[i]); } dnsSD_parseTxt(settings, nextRecord->Data.TXT.pStringArray[i]); } } break; case DNS_TYPE_SRV: if (nextRecord->wType == DNS_TYPE_SRV) { answerCount++; if (LOG_INFO <= debug) { myLog(LOG_INFO, "dnsDS_Request: DNS_TYPE_SRV %s %u", nextRecord->Data.SRV.pNameTarget, nextRecord->Data.SRV.wPort); } insertCollector(settings, nextRecord->Data.SRV.pNameTarget, nextRecord->Data.SRV.wPort); } break; default: DnsRecordListFree(pDnsRecord, dnsFreeType); myLog(LOG_ERR, "dnsDS_Request: unsupported query type %u", rtype); return -1; } nextRecord = nextRecord->pNext; } DnsRecordListFree(pDnsRecord, dnsFreeType); return answerCount; } }
void *my_os_realloc(void *ptr, size_t bytes) { myLog(LOG_INFO, "my_os_realloc(%u)", bytes); void *mem = SYS_REALLOC(ptr, bytes); if(mem == NULL) { myLog(LOG_ERR, "realloc() failed : %s", strerror(errno)); exit(EXIT_FAILURE); } return mem; }
static int parseOrResolveAddress(char *name, struct sockaddr *sa, SFLAddress *addr, int family, int numeric) { struct addrinfo *info = NULL; struct addrinfo hints = { 0 }; hints.ai_socktype = SOCK_DGRAM; // constrain this so we don't get lots of answers hints.ai_family = family; // PF_INET, PF_INET6 or 0 if(numeric) { hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; } int err = getaddrinfo(name, NULL, &hints, &info); if(err) { if(debug) myLog(LOG_INFO, "getaddrinfo() failed: %s", gai_strerror(err)); switch(err) { case EAI_NONAME: break; case EAI_NODATA: break; case EAI_AGAIN: break; // loop and try again? default: myLog(LOG_ERR, "getaddrinfo() error: %s", gai_strerror(err)); break; } return NO; } if(info == NULL) return NO; if(info->ai_addr) { // answer is now in info - a linked list of answers with sockaddr values. // extract the address we want from the first one. $$$ should perhaps // traverse the list and look for an IPv4 address since that is more // likely to work? switch(info->ai_family) { case PF_INET: { struct sockaddr_in *ipsoc = (struct sockaddr_in *)info->ai_addr; addr->type = SFLADDRESSTYPE_IP_V4; addr->address.ip_v4.addr = ipsoc->sin_addr.s_addr; if(sa) memcpy(sa, info->ai_addr, info->ai_addrlen); } break; case PF_INET6: { struct sockaddr_in6 *ip6soc = (struct sockaddr_in6 *)info->ai_addr; addr->type = SFLADDRESSTYPE_IP_V6; memcpy(&addr->address.ip_v6, &ip6soc->sin6_addr, 16); if(sa) memcpy(sa, info->ai_addr, info->ai_addrlen); } break; default: myLog(LOG_ERR, "get addrinfo: unexpected address family: %d", info->ai_family); return NO; break; } } // free the dynamically allocated data before returning freeaddrinfo(info); return YES; }
int readNioCounters(SFLHost_nio_counters *nio, char *devFilter) { int interface_count = 0; int mib[]={ CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; size_t needed=0; if(sysctl(mib, 6, NULL, &needed, NULL, 0) != 0) { myLog(LOG_ERR, "sysctl(<NioCounters>) probe failed : %s", strerror(errno)); return NO; } char *buf = (char*)my_calloc(needed); if (sysctl(mib, 6, buf, &needed, NULL, 0) != 0) { myLog(LOG_ERR, "sysctl(<NioCounters>) read failed : %s", strerror(errno)); return NO; } char *end = buf + needed; for(char *p = buf; p < end; ) { struct if_msghdr *ifm = (struct if_msghdr *)p; if(ifm->ifm_type != RTM_IFINFO) { myLog(LOG_ERR, "sysctl(<NioCounters>) walk failed (offset=%d of %d)", p - buf, needed); return NO; } p += ifm->ifm_msglen; // consume the RTM_NEWADDR msgs that follow while(p < end) { struct if_msghdr *nextifm = (struct if_msghdr *)p; if(nextifm->ifm_type != RTM_NEWADDR) break; p += nextifm->ifm_msglen; } // ignore loopback interfaces and interfaces that are currently down if(ifm->ifm_flags & IFF_LOOPBACK) continue; if(!(ifm->ifm_flags & IFF_UP)) continue; // $$$ test the device filter - is the device name known here? // may need to get the ifindex with ifm->ifm_index and then look up // the name from there - or go the other way and make the filter be // a filter on ifindex. interface_count++; // report the sum over all devices nio->bytes_in += ifm->ifm_data.ifi_ibytes; nio->pkts_in += ifm->ifm_data.ifi_ipackets; nio->errs_in += ifm->ifm_data.ifi_ierrors; nio->drops_in += ifm->ifm_data.ifi_iqdrops; nio->bytes_out += ifm->ifm_data.ifi_obytes; nio->pkts_out += ifm->ifm_data.ifi_opackets; nio->errs_out += ifm->ifm_data.ifi_oerrors; // nio->drops_out += ifm->ifm_data.ifi_oqdrops; } free(buf); return interface_count; }
void *my_os_calloc(size_t bytes) { if(debug) myLog(LOG_INFO, "my_os_calloc(%u)", bytes); void *mem = SYS_CALLOC(1, bytes); if(mem == NULL) { myLog(LOG_ERR, "calloc() failed : %s", strerror(errno)); //if(debug) malloc_stats(); exit(EXIT_FAILURE); } return mem; }
static void logSFlowSettings(HSPSFlow *sFlow) { HSPSFlowSettings *settings = sFlow->sFlowSettings; char agentAddr[255]; addrToStr(&sFlow->agentIP, agentAddr, 255); myLog(debug, "sFlow configuration agent=%s serialNumber=%u: pollingInterval=%u, samplingRate=%u", agentAddr, settings->serialNumber, settings->pollingInterval, settings->samplingRate); for (HSPCollector *collector= settings->collectors; collector; collector = collector->nxt) { myLog(debug, "collector=%s:%u", collector->name, collector->udpPort); } }
int truncateOpenFile(FILE *fptr) { int fd = fileno(fptr); if(fd == -1) { myLog(LOG_ERR, "truncateOpenFile(): fileno() failed : %s", strerror(errno)); return NO; } if(ftruncate(fd, lseek(fd, 0, SEEK_CUR)) != 0) { myLog(LOG_ERR, "truncateOpenFile(): ftruncate() failed : %s", strerror(errno)); return NO; } return YES; }
static uint32_t getRunningProcesses( void ) { struct kinfo_proc *kp; int i; int state; int nentries; kvm_t *kd = NULL; int what = KERN_PROC_ALL; uint32_t val32; val32 = 0; // it looks like we don't need to be root to call kvm_open // just to read the process table (in the way that the ps(1) command does). kd=kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY, "kvm_open"); if (kd == NULL) { myLog(LOG_ERR, "kvm_open() failed"); } else { #ifdef KERN_PROC_NOTHREADS what |= KERN_PROC_NOTHREADS; #endif if ((kp = kvm_getprocs(kd, what, 0, &nentries)) == 0 || nentries < 0) { myLog(LOG_ERR, "kvm_getprocs() failed"); } else { if(debug) myLog(LOG_INFO,"kvm_getprocs found %u entries", nentries); for (i = 0; i < nentries; kp++, i++) { #ifdef KINFO_PROC_SIZE state = kp->ki_stat; #else state = kp->kp_proc.p_stat; #endif switch(state) { case SRUN: case SIDL: val32++; break; } } } kvm_close(kd); } if (val32 > 0) val32--; // subtract one for me return val32; }
/** * Test to see whether we are running on a system with Hyper-V enabled. * We consider Hyper-V to be running (and can export per vm stats) if * the Hyper-V related services (nvspwmi, vmm, vhdsvc) are running and * we can access the WMI namespace root\virtualization (ie v1 for Win 2008). * We do not check for the v2 namespace, since this is not required for * per vm stats. * The ability connect to the sFlow filter for export of packet samples * and counter samples for the virtual switch is made separately. */ BOOL testForHyperv() { BSTR path = SysAllocString(WMI_CIMV2_NS); HRESULT hr = S_FALSE; IWbemServices *pNamespace = NULL; hr = connectToWMI(path, &pNamespace); SysFreeString(path); if (WBEM_S_NO_ERROR != hr) { myLog(LOG_ERR,"testForHyperv: connectToWMI failed for namespace %S", path); return false; } //Test for Hyper-V services BOOL gotHyperV = false; BSTR queryLang = SysAllocString(L"WQL"); BSTR query = SysAllocString(L"SELECT * FROM Win32_Service WHERE Name=\"nvspwmi\" OR Name=\"vmms\" OR Name=\"vhdsvc\""); IEnumWbemClassObject *serviceEnum = NULL; hr = pNamespace->ExecQuery(queryLang, query, WBEM_FLAG_FORWARD_ONLY, NULL, &serviceEnum); SysFreeString(query); SysFreeString(queryLang); if (WBEM_S_NO_ERROR != hr) { myLog(LOG_ERR, "testForHyperv: ExecQuery() failed for %S error=0x%x", query, hr); } else { IWbemClassObject *serviceObj = NULL; ULONG uReturned = 0; BOOL gotHyperVSvc = false; hr = serviceEnum->Next(WBEM_INFINITE, 1, &serviceObj, &uReturned); if (SUCCEEDED(hr)) { if (uReturned == 1) { gotHyperVSvc = true; serviceObj->Release(); } } serviceEnum->Release(); pNamespace->Release(); if (gotHyperVSvc) { //now check that we have the v1 virtualization namespace CoUninitialize(); path = SysAllocString(WMI_VIRTUALIZATION_NS_V1); hr = connectToWMI(path, &pNamespace); SysFreeString(path); if (WBEM_NO_ERROR == hr) { gotHyperV = true; pNamespace->Release(); } } } CoUninitialize(); myLog(LOG_INFO, "testForHyperv: HyperV=%u", gotHyperV); return gotHyperV; }
int lookupAddress(char *name, struct sockaddr *sa, SFLAddress *addr, int family) { struct addrinfo *info = NULL; struct addrinfo hints = { 0 }; hints.ai_socktype = SOCK_DGRAM; // constrain this so we don't get lots of answers hints.ai_family = family; // PF_INET, PF_INET6 or 0 int err = getaddrinfo(name, NULL, &hints, &info); if(err) { switch(err) { case EAI_NONAME: break; case EAI_NODATA: break; case EAI_AGAIN: break; // loop and try again? default: myLog(LOG_ERR, "getaddrinfo() error: %s", gai_strerror(err)); break; } return NO; } if(info == NULL) return NO; if(info->ai_addr) { // answer is now in info - a linked list of answers with sockaddr values. // extract the address we want from the first one. switch(info->ai_family) { case PF_INET: { struct sockaddr_in *ipsoc = (struct sockaddr_in *)info->ai_addr; addr->type = SFLADDRESSTYPE_IP_V4; addr->address.ip_v4.addr = ipsoc->sin_addr.s_addr; if(sa) memcpy(sa, info->ai_addr, info->ai_addrlen); } break; case PF_INET6: { struct sockaddr_in6 *ip6soc = (struct sockaddr_in6 *)info->ai_addr; addr->type = SFLADDRESSTYPE_IP_V6; memcpy(&addr->address.ip_v6, &ip6soc->sin6_addr, 16); if(sa) memcpy(sa, info->ai_addr, info->ai_addrlen); } break; default: myLog(LOG_ERR, "get addrinfo: unexpected address family: %d", info->ai_family); return NO; break; } } // free the dynamically allocated data before returning freeaddrinfo(info); return YES; }
/** * Populates the host_memory structure using data retrieved using * GlobalMemoryStatusEx function and the Memory performance counter * object. * Returns FALSE if call to GlobalMemoryStatusEx produces an error, TRUE otherwise. * Note that the Windows use of memory and classification of use does * not map cleanly to Linux terms. * Windows Resource Monitor reports cached as Standby+Modified this is not the * equivalent of Linux file system cache, however it could be viewed as * analagous memory usage, and it makes sense to retain some consistency with * Windows tools. * Windows Resource Monitor reports free memory as free and zero page list bytes, * this is used for free memory. There are no obvious equivalents for shared * and buffers so these counters are reported as unknown. * Windows also does not seem to report swapping (all memory associated with a process * swapped in/out of memory). Memory\\Pages Input/sec and Memory\\Pages Output/sec * are used for page_in and page_out. */ BOOL readMemoryCounters(SFLHost_mem_counters *mem) { MEMORYSTATUSEX memStat; memStat.dwLength = sizeof(memStat); if (GlobalMemoryStatusEx(&memStat) == 0){ myLog(LOG_ERR,"GlobalMemoryStatusEx failed: %d\n",GetLastError()); return FALSE; } mem->mem_total = memStat.ullTotalPhys; mem->swap_total = memStat.ullTotalPageFile; mem->swap_free = memStat.ullAvailPageFile; PDH_HQUERY query; if (PdhOpenQuery(NULL, 0, &query) == ERROR_SUCCESS) { PDH_HCOUNTER free, standbyCore, standbyNormal, standbyReserve, modified, pageIn, pageOut; if (addCounterToQuery(MEM_COUNTER_OBJECT, NULL, MEM_COUNTER_FREE, &query, &free) == ERROR_SUCCESS && addCounterToQuery(MEM_COUNTER_OBJECT, NULL, MEM_COUNTER_STANDBY_CORE, &query, &standbyCore) == ERROR_SUCCESS && addCounterToQuery(MEM_COUNTER_OBJECT, NULL, MEM_COUNTER_STANDBY_NORMAL, &query, &standbyNormal) == ERROR_SUCCESS && addCounterToQuery(MEM_COUNTER_OBJECT, NULL, MEM_COUNTER_STANDBY_RESERVE, &query, &standbyReserve) == ERROR_SUCCESS && addCounterToQuery(MEM_COUNTER_OBJECT, NULL, MEM_COUNTER_MODIFIED, &query, &modified) == ERROR_SUCCESS && addCounterToQuery(MEM_COUNTER_OBJECT, NULL, MEM_COUNTER_PAGE_IN, &query, &pageIn) == ERROR_SUCCESS && addCounterToQuery(MEM_COUNTER_OBJECT, NULL, MEM_COUNTER_PAGE_OUT, &query, &pageOut) == ERROR_SUCCESS && PdhCollectQueryData(query) == ERROR_SUCCESS) { mem->mem_free = getRawCounterValue(&free); mem->mem_cached = getRawCounterValue(&standbyCore) + getRawCounterValue(&standbyNormal) + getRawCounterValue(&standbyReserve) + getRawCounterValue(&modified); mem->page_in = (uint32_t)getRawCounterValue(&pageIn); mem->page_out = (uint32_t)getRawCounterValue(&pageOut); } PdhCloseQuery(query); } //There are no obvious Windows equivalents mem->mem_shared = UNKNOWN_GAUGE_64; mem->mem_buffers = UNKNOWN_GAUGE_64; //using the definition that swapping is when all the memory associated with a //process is moved in/out of RAM mem->swap_in = UNKNOWN_COUNTER; mem->swap_out = UNKNOWN_COUNTER; myLog(LOG_INFO, "readMemoryCounters:\n\ttotal: \t\t%I64d\n\tfree: \t\t%I64d\n" "\tcached: \t%I64d\n\tpage_in: \t%d\n\tpage_out: \t%d\n" "\tswap_total: \t%I64d\n\tswap_free: \t%I64d\n", mem->mem_total, mem->mem_free, mem->mem_cached, mem->page_in, mem->page_out, mem->swap_total, mem->swap_free); return TRUE; }
int selectAgentAddress(HSP *sp) { if(debug) myLog(LOG_INFO, "selectAgentAddress"); if(sp->sFlow->explicitAgentIP && sp->sFlow->agentIP.type) { // it was hard-coded in the config file if(debug) myLog(LOG_INFO, "selectAgentAddress hard-coded in config file"); return YES; } // it may have been defined as agent=<device> if(sp->sFlow->explicitAgentDevice && sp->sFlow->agentDevice) { SFLAdaptor *ad = adaptorListGet(sp->adaptorList, sp->sFlow->agentDevice); if(ad && ad->userData) { HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)ad->userData; sp->sFlow->agentIP = adaptorNIO->ipAddr; if(debug) myLog(LOG_INFO, "selectAgentAddress pegged to device in config file"); return YES; } } // try to automatically choose an IP (or IPv6) address, based on the priority ranking. // We already used this ranking to prioritize L3 addresses per adaptor (in the case where // there are more than one) so now we are applying the same ranking globally to pick // the best candidate to represent the whole agent: SFLAdaptor *selectedAdaptor = NULL; EnumIPSelectionPriority ipPriority = IPSP_NONE; for(uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) { SFLAdaptor *adaptor = sp->adaptorList->adaptors[i]; if(adaptor && adaptor->userData) { HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)adaptor->userData; if(adaptorNIO->ipPriority > ipPriority) { selectedAdaptor = adaptor; ipPriority = adaptorNIO->ipPriority; } } } if(selectedAdaptor && selectedAdaptor->userData) { // crown the winner HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)selectedAdaptor->userData; sp->sFlow->agentIP = adaptorNIO->ipAddr; sp->sFlow->agentDevice = my_strdup(selectedAdaptor->deviceName); if(debug) myLog(LOG_INFO, "selectAgentAddress selected agentIP with highest priority"); return YES; } return NO; }
static void agentCB_sendPkt(void *magic, SFLAgent *agent, SFLReceiver *receiver, u_char *pkt, uint32_t pktLen) { HSP *sp = (HSP *)magic; size_t socklen = 0; int fd = 0; for(HSPCollector *coll = sp->sFlow->sFlowSettings->collectors; coll; coll=coll->nxt) { switch(coll->ipAddr.type) { case SFLADDRESSTYPE_UNDEFINED: // skip over it if the forward lookup failed break; case SFLADDRESSTYPE_IP_V4: { struct sockaddr_in *sa = (struct sockaddr_in *)&(coll->sendSocketAddr); socklen = sizeof(struct sockaddr_in); sa->sin_family = AF_INET; sa->sin_port = htons(coll->udpPort); fd = sp->socket4; } break; case SFLADDRESSTYPE_IP_V6: { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&(coll->sendSocketAddr); socklen = sizeof(struct sockaddr_in6); sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(coll->udpPort); fd = sp->socket6; } break; } if(socklen && fd > 0) { int result = sendto(fd, pkt, pktLen, 0, (struct sockaddr *)&coll->sendSocketAddr, socklen); if(result == -1 && errno != EINTR) { myLog(LOG_ERR, "socket sendto error: %s", strerror(errno)); } if(result == 0) { myLog(LOG_ERR, "socket sendto returned 0: %s", strerror(errno)); } } } }
void readVLANs(HSP *sp) { // mark interfaces that are specific to a VLAN FILE *procFile = fopen("/proc/net/vlan/config", "r"); if(procFile) { char line[MAX_PROC_LINE_CHARS]; int lineNo = 0; while(fgets(line, MAX_PROC_LINE_CHARS, procFile)) { // expect lines of the form "<device> VID: <vlan> ..." // (with a header line on the first row) char devName[MAX_PROC_LINE_CHARS]; int vlan; ++lineNo; if(lineNo > 1 && sscanf(line, "%s | %d", devName, &vlan) == 2) { SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, trimWhitespace(devName)); if(adaptor && adaptor->userData && vlan >= 0 && vlan < 4096) { HSPAdaptorNIO *niostate = (HSPAdaptorNIO *)adaptor->userData; niostate->vlan = vlan; if(debug) myLog(LOG_INFO, "adaptor %s has 802.1Q vlan %d", devName, vlan); } } } fclose(procFile); } }
/* Returns a pointer to an array which is the starting of adjList */ AdjList* initAdjList() { AdjList *pstAdjList = NULL_PTR; int i, size; size = gNoOfVertex; /*Allocate the size of the array. Each array index will maintain a list If 2 is connected to 5 with edge weight 10, at piAdjList[1], next will point to a node whose vertextNum is 5 and distance is 10. */ pstAdjList = (AdjList *) malloc(sizeof(AdjList)*size); /* If memory was allocted */ if (NULL_PTR == pstAdjList) { myLog(ERROR, "malloc failed!"); return NULL_PTR; } /* Initialize */ for (i = 0; i < size; i++) { pstAdjList[i].vertexNum = i; pstAdjList[i].distance = 0; pstAdjList[i].next = NULL_PTR; } return pstAdjList; }
ULONG_PTR setFilterSamplingParams(HSP *sp) { BOOLEAN ioctlSuccess; uint32_t tries = 0; ULONG_PTR error = ERROR_SUCCESS; SFlowConfiguration sFlowConfig; sFlowConfig.sampleRate = sp->sFlow->sFlowSettings->samplingRate; sFlowConfig.sampleHeaderLength = sp->sFlow->sFlowSettings->headerBytes; do { ioctlSuccess = DeviceIoControl(sp->filter.dev, IOCTL_SFLOW_CONFIGURE, &sFlowConfig, sizeof(SFlowConfiguration), NULL, 0, NULL, &sp->filter.ioctlOverlap); if (!ioctlSuccess) { error = GetLastError(); if (error == ERROR_IO_PENDING) { // I/O pending, wait for completion if (WaitForSingleObject(sp->filter.ioctlOverlap.hEvent, INFINITE) == WAIT_OBJECT_0) { error = sp->filter.ioctlOverlap.Internal; } } } tries++; } while (tries < 10 && error == ERROR_GEN_FAILURE); if (tries >= 10 || error == ERROR_GEN_FAILURE) { myLog(LOG_ERR, "SetFilterSamplerSettings: failed"); } return error; }
/* Deallocates memory used by the adj list */ void destroyAdjList(AdjList *pstAdjList) { int i, j; AdjList *pstTraverser = NULL_PTR, *pstTmp = NULL_PTR; if (NULL_PTR == pstAdjList) { myLog(ERROR, "Invalid Input!"); return; } for (i = 0; i < gNoOfVertex; i++) { pstTraverser = &(pstAdjList[i]); /* Delete the horizontal lists */ while (NULL_PTR != pstTraverser->next) { pstTmp = pstTraverser->next; pstTraverser->next = pstTmp->next; free(pstTmp); pstTmp = NULL_PTR; } } /* Delete the vertical list */ free(pstAdjList); pstAdjList = NULL_PTR; }
static HSPToken *readTokens(HSP *sp) { FILE *cfg = NULL; if((cfg = fopen(sp->configFile, "r")) == NULL) { myLog(LOG_ERR,"cannot open config file %s : %s", sp->configFile, strerror(errno)); return NULL; } // collect the tokens in a (reversed) list HSPToken *tokens = newToken("start", 5); char line[HSP_MAX_LINELEN]; uint32_t lineNo = 0; while(fgets(line, HSP_MAX_LINELEN, cfg)) { lineNo++; char *p = line; // comments start with '#' p[strcspn(p, "#")] = '\0'; HSPToken *tok; while((tok = nextToken(p, &p)) != NULL) { tok->lineNo = lineNo; ADD_TO_LIST(tokens, tok); } } fclose(cfg); // get them in the right order tokens = reverseTokens(tokens); return tokens; }
static bool readConfig(EVMod *mod) { HSP_mod_OVS *mdata = (HSP_mod_OVS *)mod->data; HSP *sp = (HSP *)EVROOTDATA(mod); resetConfig(&mdata->config); if(sp->sFlowSettings == NULL) return NO; mdata->config.sampling_n = sp->sFlowSettings->samplingRate; mdata->config.polling_secs = sp->actualPollingInterval; mdata->config.header_bytes = sp->sFlowSettings->headerBytes; char ipbuf[51]; SFLAddress_print(&sp->agentIP, ipbuf, 50); setStr(&mdata->config.agent_ip, ipbuf); setStr(&mdata->config.agent_dev, sp->agentDevice); for(HSPCollector *coll = sp->sFlowSettings->collectors; coll; coll = coll->nxt) { if(mdata->config.num_collectors == SFVS_MAX_COLLECTORS) { myLog(LOG_ERR, "OVS: MAX collectors exceeded"); } else { uint32_t i = mdata->config.num_collectors++; SFLAddress_print(&coll->ipAddr, ipbuf, 50); setStr(&mdata->config.collectors[i].ip, ipbuf); mdata->config.collectors[i].port = coll->udpPort; mdata->config.collectors[i].priority = 0; } } // turn the collectors list into the targets string formatTargets(mod); return YES; }
/** * Enumerates MSFT_NetIpAddress whose interface index is the same as the * adaptor's. Calls stringToAdaptorIP() for each object so that the * highest priority IP address is associated with the adaptor. */ static void readIpAddressesMsft(IWbemServices *pNamespace, SFLAdaptor *adaptor) { BSTR queryLang = SysAllocString(L"WQL"); wchar_t *query = L"SELECT * FROM MSFT_NetIpAddress WHERE InterfaceIndex=%u"; wchar_t ipQuery[70]; swprintf_s(ipQuery, 70, query, adaptor->ifIndex); IEnumWbemClassObject *ipEnum = NULL; HRESULT hr = pNamespace->ExecQuery(queryLang, ipQuery, WBEM_FLAG_FORWARD_ONLY, NULL, &ipEnum); SysFreeString(queryLang); if (!SUCCEEDED(hr)) { myLog(LOG_ERR,"readIpAddressesMsft: ExecQuery() failed for query %S error=0x%x", ipQuery, hr); return; } IWbemClassObject *ipObj; hr = WBEM_S_NO_ERROR; while (WBEM_S_NO_ERROR == hr) { ULONG ipCount = 0; hr = ipEnum->Next(WBEM_INFINITE, 1, &ipObj, &ipCount); if (ipCount == 0) { break; } VARIANT address; hr = ipObj->Get(L"IPAddress", 0, &address, 0, 0); if (WBEM_S_NO_ERROR == hr && V_VT(&address) == VT_BSTR) { stringToAdaptorIp(address.bstrVal, adaptor); } VariantClear(&address); ipObj->Release(); } ipEnum->Release(); }
void adaptorListFreeMarked(SFLAdaptorList *adList) { uint32_t removed = 0; for(uint32_t i = 0; i < adList->num_adaptors; i++) { SFLAdaptor *ad = adList->adaptors[i]; if(ad && ad->marked) { adaptorFree(ad); adList->adaptors[i] = NULL; removed++; } } if(removed > 0) { uint32_t found = 0; // now pack the array and update the num_adaptors count for(uint32_t i = 0; i < adList->num_adaptors; i++) { SFLAdaptor *ad = adList->adaptors[i]; if(ad) adList->adaptors[found++] = ad; } // cross-check if((found + removed) != adList->num_adaptors) { myLog(LOG_ERR, "adaptorListFreeMarked: found(%u) + removed(%u) != num_adaptors(%u)", found, removed, adList->num_adaptors); } adList->num_adaptors = found; } }