static SFLSampler *getSampler(HSP *sp, char *devName, uint32_t ifIndex) { SFLSampler *sampler = sfl_agent_getSamplerByIfIndex(sp->sFlow->agent, ifIndex); if(sampler == NULL) { SFLDataSource_instance dsi; SFL_DS_SET(dsi, 0, ifIndex, 0); // ds_class,ds_index,ds_instance HSPSFlow *sf = sp->sFlow; // add sampler (with sub-sampling rate), and poller too uint32_t samplingRate = sf->sFlowSettings->ulogSubSamplingRate; sampler = sfl_agent_addSampler(sf->agent, &dsi); sfl_sampler_set_sFlowFsPacketSamplingRate(sampler, samplingRate); sfl_sampler_set_sFlowFsReceiver(sampler, HSP_SFLOW_RECEIVER_INDEX); if(devName) { uint32_t pollingInterval = sf->sFlowSettings ? sf->sFlowSettings->pollingInterval : SFL_DEFAULT_POLLING_INTERVAL; SFLPoller *poller = sfl_agent_addPoller(sf->agent, &dsi, sp, agentCB_getCounters_interface); sfl_poller_set_sFlowCpInterval(poller, pollingInterval); sfl_poller_set_sFlowCpReceiver(poller, HSP_SFLOW_RECEIVER_INDEX); // remember the device name to make the lookups easier later. // Don't want to point directly to the SFLAdaptor or SFLAdaptorNIO object // in case it gets freed at some point. The device name is enough. poller->userData = (void *)my_strdup(devName); } } return sampler; }
/** * If the polling interval is > 0, adds an interface counter poller to * sp->sFlow->agent or the adaptor representing the switch port. Returns * the added poller, or NULL if a poller was not added. */ static SFLPoller *addPoller(HSP *sp, SFLAdaptor *adaptor) { uint32_t pollingInterval = sp->sFlow->sFlowSettings ? sp->sFlow->sFlowSettings->pollingInterval : SFL_DEFAULT_POLLING_INTERVAL; if (pollingInterval <= 0) { return NULL; } SFLDataSource_instance switchDsi; SFL_DS_SET(switchDsi, SFL_DSCLASS_IFINDEX, adaptor->ifIndex, 0); SFLPoller *poller = sfl_agent_addPoller(sp->sFlow->agent, &switchDsi, sp, agentCB_getCounters); // remember the deviceName to make the lookups easier later. // We don't point directly to the SFLAdaptor object // in case it gets freed at some point. The deviceName is enough. poller->userData = my_strdup(adaptor->deviceName); myLog(LOG_INFO, "addPoller: added counter poller for %lu %s", adaptor->ifIndex, adaptor->deviceName); sfl_poller_set_sFlowCpInterval(poller, pollingInterval); sfl_poller_set_sFlowCpReceiver(poller, HSP_SFLOW_RECEIVER_INDEX); return poller; }
static SFLPoller *getPoller(HSP *sp, SFLAdaptor *adaptor) { HSPAdaptorNIO *adaptorNIO=(HSPAdaptorNIO *)adaptor->userData; if(adaptorNIO) { if(adaptorNIO->poller == NULL) { SFLDataSource_instance dsi; SFL_DS_SET(dsi, 0, adaptor->ifIndex, 0); // ds_class,ds_index,ds_instance HSPSFlow *sf = sp->sFlow; uint32_t pollingInterval = sf->sFlowSettings ? sf->sFlowSettings->pollingInterval : SFL_DEFAULT_POLLING_INTERVAL; adaptorNIO->poller = sfl_agent_addPoller(sf->agent, &dsi, sp, agentCB_getCounters_interface); sfl_poller_set_sFlowCpInterval(adaptorNIO->poller, pollingInterval); sfl_poller_set_sFlowCpReceiver(adaptorNIO->poller, HSP_SFLOW_RECEIVER_INDEX); // remember the device name to make the lookups easier later. // Don't want to point directly to the SFLAdaptor or SFLAdaptorNIO object // in case it gets freed at some point. The device name is enough. adaptorNIO->poller->userData = (void *)my_strdup(adaptor->deviceName); } return adaptorNIO->poller; } return NULL; }
static BOOL initAgent(HSP *sp) { time_t now; HSPCollector *collector; SFLReceiver *receiver; uint32_t receiverIndex; SFLDataSource_instance dsi; uint32_t pollingInterval; HSPSFlow *sf = sp->sFlow; WSADATA WSAData; int WSARes = 0; myLog(LOG_INFO,"creating sfl agent\n"); if (sf->collectors == NULL) { myLog(LOG_ERR,"No collectors defined\n"); return FALSE; } assert(sf->agentIP.type); WORD word = MAKEWORD(2, 2); WSARes = WSAStartup(word,&WSAData); if (WSARes != 0) { myLog(LOG_ERR,"WSAStartup failed: %d",WSARes); exit(WSARes); } // open the sockets if not open already - one for v4 and another for v6 if (sp->socket4 <= 0) { if ((sp->socket4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { myLog(LOG_ERR,"socket error"); } } if (sp->socket6 <= 0) { if ((sp->socket6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) { myLog(LOG_ERR,"socket error"); } } time(&now); sf->agent = (SFLAgent *)my_calloc(sizeof(SFLAgent)); sfl_agent_init(sf->agent, &sf->agentIP, sf->subAgentId, now, now, sp, agentCB_alloc, agentCB_free, agentCB_error, agentCB_sendPkt); // just one receiver - we are serious about making this lightweight for now collector = sf->collectors; receiver = sfl_agent_addReceiver(sf->agent); receiverIndex = HSP_SFLOW_RECEIVER_INDEX; // set the default receiver owner string sfl_receiver_set_sFlowRcvrOwner(receiver, "HyperV sFlow Agent"); // set the timeout to infinity sfl_receiver_set_sFlowRcvrTimeout(receiver, 0xFFFFFFFF); // receiver address/port - set it for the first collector, but // actually we'll send the same feed to all collectors. This step // may not be necessary at all when we are using the sendPkt callback. sfl_receiver_set_sFlowRcvrAddress(receiver, &collector->ipAddr); sfl_receiver_set_sFlowRcvrPort(receiver, collector->udpPort); pollingInterval = sf->sFlowSettings ? sf->sFlowSettings->pollingInterval : SFL_DEFAULT_POLLING_INTERVAL; // add a single poller to represent the whole physical host if (pollingInterval > 0) { // ds_class = <physicalEntity>, ds_index = <my physical>, ds_instance = 0 SFL_DS_SET(dsi, SFL_DSCLASS_PHYSICAL_ENTITY, HSP_DEFAULT_PHYSICAL_DSINDEX, 0); sf->poller = sfl_agent_addPoller(sf->agent, &dsi, sp, agentCB_getCounters); sfl_poller_set_sFlowCpInterval(sf->poller, pollingInterval); sfl_poller_set_sFlowCpReceiver(sf->poller, receiverIndex); } return TRUE; }
void ServiceMain(int argc, char** argv) { ServiceStatus.dwServiceType = SERVICE_WIN32; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; if (isService) { hStatus = RegisterServiceCtrlHandler(HSP_SERVICE_NAME, (LPHANDLER_FUNCTION)ControlHandler); if (hStatus == 0) { return; } } // Test for only one instance is running HANDLE mutex = CreateMutex(NULL, TRUE, instanceMutexName); DWORD err = GetLastError(); if (mutex != NULL && err == ERROR_ALREADY_EXISTS || mutex == NULL && err == ERROR_ACCESS_DENIED) { // Mutex found, so another instance is running if (hStatus != 0) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = ERROR_SINGLE_INSTANCE_APP; SetServiceStatus(hStatus, &ServiceStatus); } else { myLog(LOG_ERR, "%s.ServiceMain: only one instance can run, existing instance found", HSP_SERVICE_NAME); } return; } else { ServiceStatus.dwCurrentState = SERVICE_RUNNING; if (hStatus != 0) { // We are the first instance, report the running status to SCM. SetServiceStatus (hStatus, &ServiceStatus); } } wchar_t programDataDir[MAX_PATH]; if (!initialiseProgramDataDir(programDataDir, MAX_PATH)) { *programDataDir = NULL; } char mbcLogFilename[MAX_PATH]; if (isService && *programDataDir != NULL) { //set the log file name to the default. size_t dirLen = 0; if (0 == wcstombs_s(&dirLen, mbcLogFilename, MAX_PATH, programDataDir, wcslen(programDataDir))) { PathAppend(mbcLogFilename, HSP_DEFAULT_LOGFILE); logFilename = mbcLogFilename; } else { logFilename = NULL; } } if (logFilename != NULL) { // Logging on errno_t error = fopen_s(&logFile, logFilename, "wt"); if (error != 0) { logFile = stderr; myLog(LOG_ERR, "%s.ServiceMain: could not open log file %s: error %d\n", HSP_SERVICE_NAME, logFilename, error); } logFilename = NULL; } myLog(debug, "-------------Starting %s %s--------------", HSP_SERVICE_NAME, HSP_VERSION); fflush(logFile); HRESULT initComHr = initCom(); if (FAILED(initComHr)) { myLog(LOG_ERR, "%s.ServiceMain: cannot initialize COM for WMI error=0x%x", HSP_SERVICE_NAME, initComHr); if (hStatus != 0) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = ERROR_APP_INIT_FAILURE; SetServiceStatus(hStatus, &ServiceStatus); } return; } HSP sp = { 0 }; sp.DNSSD_startDelay = HSP_DEFAULT_DNSSD_STARTDELAY; sp.DNSSD_retryDelay = HSP_DEFAULT_DNSSD_RETRYDELAY; // look up host-id fields at startup only (hostname // may change dynamically so will have to revisit this $$$) sp.host_hid.hostname.str = (char *)my_calloc(SFL_MAX_HOSTNAME_CHARS+1); sp.host_hid.os_release.str = (char *)my_calloc(SFL_MAX_OSRELEASE_CHARS+1); readHidCounters(&sp, &sp.host_hid); sp.nio_polling_secs = HSP_NIO_POLLING_SECS_32BIT; readInterfaces(&sp, TRUE); if (!readConfig(&sp)) { myLog(LOG_ERR, "%s.ServiceMain: invalid configuration", HSP_SERVICE_NAME); if (hStatus != 0) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = ERROR_INVALID_PARAMETER; SetServiceStatus(hStatus, &ServiceStatus); } return; } sp.hyperV = testForHyperv(); if (sp.hyperV) { myLog(debug, "%s.ServiceMain Hyper-V services are running", HSP_SERVICE_NAME); if (programDataDir == NULL || !initialiseProgramDataFiles(&sp, programDataDir)) { myLog(LOG_ERR, "%s.ServiceMain: cannot initialise switch port and VM state files", HSP_SERVICE_NAME); if (hStatus != 0) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = ERROR_FILE_NOT_FOUND; SetServiceStatus(hStatus, &ServiceStatus); } return; } readGuidStore(sp.f_vmStore, sp.vmStoreFile, &sp.vmStore, &sp.maxDsIndex); readGuidStore(sp.f_portStore, sp.portStoreFile, &sp.portStore, &sp.maxIfIndex); } if (sp.DNSSD) { //start the DNS thread and loop waiting until we have the config from DNSSD HANDLE dnsSDThread; unsigned threadID; dnsSDThread = (HANDLE)_beginthreadex(NULL, 0, &runDNSSD, &sp, 0, &threadID); BOOL gotConfig = FALSE; while (!gotConfig) { HSPSFlowSettings *settings = sp.sFlow->sFlowSettings; if (newerSettingsAvailable(settings)) { HSPSFlowSettings *newSettings = newSFlowSettings(); if (readSFlowSettings(newSettings)) { //we have the config now gotConfig = TRUE; if (settings != NULL) { freeSFlowSettings(settings); } sp.sFlow->sFlowSettings = newSettings; myLog(debug, "%s.ServiceMain: DNS-SD enabled. Initial sFlow settings from registry currentconfig", HSP_SERVICE_NAME); } else { freeSFlowSettings(newSettings); myLog(LOG_ERR, "%s.ServiceMain: invalid DNS-SD discovered sFlow settings", HSP_SERVICE_NAME); if (hStatus != 0) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = ERROR_INVALID_PARAMETER; SetServiceStatus(hStatus, &ServiceStatus); } return; } } else { Sleep(sp.DNSSD_startDelay*1000); } } } else { // read the manual config HSPSFlowSettings *newSettings = newSFlowSettings(); if (readSFlowSettings(newSettings)) { sp.sFlow->sFlowSettings = newSettings; } else { myLog(LOG_ERR, "%s.ServiceMain: invalid sFlow configuration in registry", HSP_SERVICE_NAME); if (hStatus != 0) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = ERROR_INVALID_PARAMETER; SetServiceStatus(hStatus, &ServiceStatus); } return; } } openFilter(&sp); //try to initialise the sFlow filter for sampling initAgent(&sp); logSFlowSettings(sp.sFlow); // initialize the clock so we can detect second boundaries sp.clk = time(NULL); // main loop BOOL dataAvailable = true; uint32_t currReadNum = 0; while (ServiceStatus.dwCurrentState == SERVICE_RUNNING && dataAvailable) { // check for second boundaries and generate ticks for the sFlow library time_t now = time(NULL); if ((now < sp.clk) || (now - sp.clk) > HSP_MAX_TICKS) { // avoid a busy-loop of ticks if time jumps myLog(LOG_INFO, "%s.ServiceMain: time jump detected", HSP_SERVICE_NAME); sp.clk = now - 1; } while (sp.clk < now) { //only happens on second boundary //start critical if (sp.sFlow->sFlowSettings) { if (sp.clk%5 == 0 && newerSettingsAvailable(sp.sFlow->sFlowSettings)) { //get the new config HSPSFlowSettings *newSettings = newSFlowSettings(); if (readSFlowSettings(newSettings)) { //we have the config now BOOL pollingChanged = sp.sFlow->sFlowSettings->pollingInterval != newSettings->pollingInterval; BOOL samplingChanged = sp.sFlow->sFlowSettings->samplingRate != newSettings->samplingRate; freeSFlowSettings(sp.sFlow->sFlowSettings); sp.sFlow->sFlowSettings = newSettings; myLog(debug, "%s.ServiceMain: updated configuration settings", HSP_SERVICE_NAME); logSFlowSettings(sp.sFlow); if (pollingChanged) { for (SFLPoller *poller = sp.sFlow->agent->pollers; poller; poller = poller->nxt) { sfl_poller_set_sFlowCpInterval(poller, sp.sFlow->sFlowSettings->pollingInterval); } } if (samplingChanged && HSP_FILTER_ACTIVE(sp.filter)) { setFilterSamplingParams(&sp); } } else { freeSFlowSettings(newSettings); } } tick(&sp); } //end critical sp.clk++; } DWORD result; //process a queued counter poller processQueuedPoller(&sp); //timeout is set so that we loop around checking for ticks and samples //several times/s. //calculate timeout 200 if the counter poller queue is empty, 0 otherwise DWORD timeout = sp.pollerQHead == NULL ? HSP_TIMEOUT : 0; if (HSP_FILTER_ACTIVE(sp.filter)) { result = WaitForSingleObject(sp.filter.overlaps[currReadNum].hEvent, timeout); if (result == WAIT_OBJECT_0) { dataAvailable = sp.filter.overlaps[currReadNum].Internal == ERROR_SUCCESS; if (dataAvailable && sp.filter.overlaps[currReadNum].InternalHigh > 0) { //process the sample info in sp.filter.buffers[currReadNum] readPackets(&sp, sp.filter.buffers[currReadNum]); } // Re-queue this read queueRead(sp.filter.dev, sp.filter.buffers[currReadNum], sizeof(sp.filter.buffers[currReadNum]), &sp.filter.overlaps[currReadNum]); //set the next buffer to read currReadNum = (currReadNum+1)%numConcurrentReads; } } else { Sleep(timeout); } } return; }
static int initAgent(HSP *sp) { time_t now; HSPCollector *collector; SFLReceiver *receiver; uint32_t receiverIndex; SFLDataSource_instance dsi; uint32_t pollingInterval; HSPSFlow *sf = sp->sFlow; WSADATA WSAData; int WSARes = 0; MyLog(LOG_ERR,"creating sfl agent\n"); if(sf->collectors == NULL) { MyLog(LOG_ERR,"No collectors defined\n"); return NO; } assert(sf->agentIP.type); WSARes = WSAStartup(MAKEWORD(2, 2),&WSAData); if(WSARes != 0){ MyLog(LOG_ERR,"WSAStartup failed: %d\n",WSARes); exit(WSARes); } // open the sockets if not open already - one for v4 and another for v6 if(sp->socket4 <= 0) { if((sp->socket4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) MyLog(LOG_ERR,"socket error"); } if(sp->socket6 <= 0) { if((sp->socket6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) MyLog(LOG_ERR,"socket error"); } time(&now); sf->agent = (SFLAgent *)calloc(1, sizeof(SFLAgent)); sfl_agent_init(sf->agent, &sf->agentIP, sf->subAgentId, now, now, sp, agentCB_alloc, agentCB_free, agentCB_error, agentCB_sendPkt); // just one receiver - we are serious about making this lightweight for now collector = sf->collectors; receiver = sfl_agent_addReceiver(sf->agent); receiverIndex = 1; // claim the receiver slot sfl_receiver_set_sFlowRcvrOwner(receiver, "Virtual Switch sFlow Probe"); // set the timeout to infinity sfl_receiver_set_sFlowRcvrTimeout(receiver, 0xFFFFFFFF); // receiver address/port - set it for the first collector, but // actually we'll send the same feed to all collectors. This step // may not be necessary at all when we are using the sendPkt callback. sfl_receiver_set_sFlowRcvrAddress(receiver, &collector->ipAddr); sfl_receiver_set_sFlowRcvrPort(receiver, collector->udpPort); pollingInterval = sf->sFlowSettings ? sf->sFlowSettings->pollingInterval : SFL_DEFAULT_POLLING_INTERVAL; // add a single poller to represent the whole physical host SFL_DS_SET(dsi, 2, 1, 0); // ds_class = <physicalEntity>, ds_index = 1, ds_instance = 0 sf->poller = sfl_agent_addPoller(sf->agent, &dsi, sp, agentCB_getCounters); sfl_poller_set_sFlowCpInterval(sf->poller, pollingInterval); sfl_poller_set_sFlowCpReceiver(sf->poller, receiverIndex); // add poller instances for each virtual machine $$$ return YES; }