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;
}
Exemple #3
0
  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;
  }
Exemple #4
0
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;
}
Exemple #5
0
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; 
}
Exemple #6
0
  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;
  }