SFLSampler *sfl_agent_addSampler(SFLAgent *agent, SFLDataSource_instance *pdsi) { /* Keep the list sorted. */ SFLSampler *prev = NULL, *sm = agent->samplers; for(; sm != NULL; prev = sm, sm = sm->nxt) { int64_t cmp = sfl_dsi_compare(pdsi, &sm->dsi); if(cmp == 0) return sm; /* found - return existing one */ if(cmp < 0) break; /* insert here */ } /* either we found the insert point, or reached the end of the list...*/ { SFLSampler *newsm = (SFLSampler *)sflAlloc(agent, sizeof(SFLSampler)); sfl_sampler_init(newsm, agent, pdsi); if(prev) prev->nxt = newsm; else agent->samplers = newsm; newsm->nxt = sm; /* see if we should go in the ifIndex jumpTable */ if(SFL_DS_CLASS(newsm->dsi) == 0) { SFLSampler *test = sfl_agent_getSamplerByIfIndex(agent, SFL_DS_INDEX(newsm->dsi)); if(test && (SFL_DS_INSTANCE(newsm->dsi) < SFL_DS_INSTANCE(test->dsi))) { /* replace with this new one because it has a lower ds_instance number */ sfl_agent_jumpTableRemove(agent, test); test = NULL; } if(test == NULL) sfl_agent_jumpTableAdd(agent, newsm); } return newsm; } }
static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler) { u_int32_t hashIndex = SFL_DS_INDEX(sampler->dsi) % SFL_HASHTABLE_SIZ; SFLSampler *search = agent->jumpTable[hashIndex], *prev = NULL; for( ; search != NULL; prev = search, search = search->hash_nxt) if(search == sampler) break; if(search) { // found - unlink if(prev) prev->hash_nxt = search->hash_nxt; else agent->jumpTable[hashIndex] = search->hash_nxt; search->hash_nxt = NULL; } }
void sfl_poller_writeCountersSample(SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs) { /* fill in the rest of the header fields, and send to the receiver */ cs->sequence_number = ++poller->countersSampleSeqNo; #ifdef SFL_USE_32BIT_INDEX cs->ds_class = SFL_DS_CLASS(poller->dsi); cs->ds_index = SFL_DS_INDEX(poller->dsi); #else cs->source_id = SFL_DS_DATASOURCE(poller->dsi); #endif /* sent to my receiver */ if(poller->myReceiver) sfl_receiver_writeCountersSample(poller->myReceiver, cs); }
void sfl_sampler_writeFlowSample(SFLSampler *sampler, SFL_FLOW_SAMPLE_TYPE *fs) { if(fs == NULL) return; sampler->samplesThisTick++; /* increment the sequence number */ fs->sequence_number = ++sampler->flowSampleSeqNo; /* copy the other header fields in */ #ifdef SFL_USE_32BIT_INDEX fs->ds_class = SFL_DS_CLASS(sampler->dsi); fs->ds_index = SFL_DS_INDEX(sampler->dsi); #else fs->source_id = SFL_DS_DATASOURCE(sampler->dsi); #endif /* the sampling rate may have been set already. */ if(fs->sampling_rate == 0) fs->sampling_rate = sampler->sFlowFsPacketSamplingRate; /* the samplePool may be maintained upstream too. */ if( fs->sample_pool == 0) fs->sample_pool = sampler->samplePool; /* sent to my receiver */ if(sampler->myReceiver) sfl_receiver_writeFlowSample(sampler->myReceiver, fs); }
SFLSampler *sfl_agent_getSamplerByIfIndex(SFLAgent *agent, u_int32_t ifIndex) { SFLSampler *search = agent->jumpTable[ifIndex % SFL_HASHTABLE_SIZ]; for( ; search != NULL; search = search->hash_nxt) if(SFL_DS_INDEX(search->dsi) == ifIndex) break; return search; }
static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler) { u_int32_t hashIndex = SFL_DS_INDEX(sampler->dsi) % SFL_HASHTABLE_SIZ; sampler->hash_nxt = agent->jumpTable[hashIndex]; agent->jumpTable[hashIndex] = sampler; }
void agentCB_getCountersVM(void *magic, SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs) { #ifdef HSF_XEN assert(poller->magic); HSP *sp = (HSP *)poller->magic; HSPVMState *state = (HSPVMState *)poller->userData; if(state && xenHandlesOK(sp)) { uint32_t dom_id = SFL_DS_INDEX(poller->dsi); xc_domaininfo_t domaininfo; int32_t n = xc_domain_getinfolist(sp->xc_handle, state->vm_index, 1, &domaininfo); if(n < 0 || domaininfo.domain != dom_id) { // Assume something changed under our feet. // Request a reload of the VM information and bail. // We'll try again next time. myLog(LOG_INFO, "request for vm_index %u (dom_id=%u) returned %d (with dom_id=%u)", state->vm_index, dom_id, n, domaininfo.domain); sp->refreshVMList = YES; return; } // host ID SFLCounters_sample_element hidElem = { 0 }; memset(&hidElem, 0, sizeof(hidElem)); hidElem.tag = SFLCOUNTERS_HOST_HID; char query[255]; char hname[255]; snprintf(query, sizeof(query), "/local/domain/%u/name", dom_id); char *xshname = (char *)xs_read(sp->xs_handle, XBT_NULL, query, NULL); if(xshname) { // copy the name out here so we can free it straight away strncpy(hname, xshname, 255); free(xshname); hidElem.counterBlock.host_hid.hostname.str = hname; hidElem.counterBlock.host_hid.hostname.len = strlen(hname); memcpy(hidElem.counterBlock.host_hid.uuid, &domaininfo.handle, 16); hidElem.counterBlock.host_hid.machine_type = SFLMT_unknown; hidElem.counterBlock.host_hid.os_name = SFLOS_unknown; //hidElem.counterBlock.host_hid.os_release.str = NULL; //hidElem.counterBlock.host_hid.os_release.len = 0; SFLADD_ELEMENT(cs, &hidElem); } // host parent SFLCounters_sample_element parElem = { 0 }; parElem.tag = SFLCOUNTERS_HOST_PAR; parElem.counterBlock.host_par.dsClass = SFL_DSCLASS_PHYSICAL_ENTITY; parElem.counterBlock.host_par.dsIndex = 1; SFLADD_ELEMENT(cs, &parElem); // VM Net I/O SFLCounters_sample_element nioElem = { 0 }; nioElem.tag = SFLCOUNTERS_HOST_VRT_NIO; char devFilter[20]; snprintf(devFilter, 20, "vif%u.", dom_id); uint32_t network_count = readNioCounters((SFLHost_nio_counters *)&nioElem.counterBlock.host_vrt_nio, devFilter); if(state->network_count != network_count) { // request a refresh if the number of VIFs changed. Not a perfect test // (e.g. if one was removed and another was added at the same time then // we would miss it). I guess we should keep the whole list of network ids, // or just force a refresh every few minutes? myLog(LOG_INFO, "vif count changed from %u to %u (dom_id=%u). Setting refreshAdaptorList=YES", state->network_count, network_count, dom_id); state->network_count = network_count; sp->refreshAdaptorList = YES; } SFLADD_ELEMENT(cs, &nioElem); // VM cpu counters [ref xenstat.c] SFLCounters_sample_element cpuElem = { 0 }; cpuElem.tag = SFLCOUNTERS_HOST_VRT_CPU; u_int64_t vcpu_ns = 0; for(uint32_t c = 0; c <= domaininfo.max_vcpu_id; c++) { xc_vcpuinfo_t info; if(xc_vcpu_getinfo(sp->xc_handle, dom_id, c, &info) != 0) { // error or domain is in transition. Just bail. myLog(LOG_INFO, "vcpu list in transition (dom_id=%u)", dom_id); return; } else { if(info.online) { vcpu_ns += info.cpu_time; } } } uint32_t st = domaininfo.flags; // first 8 bits (b7-b0) are a mask of flags (see tools/libxc/xen/domctl.h) // next 8 bits (b15-b8) indentify the CPU to which the domain is bound // next 8 bits (b23-b16) indentify the the user-supplied shutdown code cpuElem.counterBlock.host_vrt_cpu.state = SFL_VIR_DOMAIN_NOSTATE; if(st & XEN_DOMINF_shutdown) { cpuElem.counterBlock.host_vrt_cpu.state = SFL_VIR_DOMAIN_SHUTDOWN; if(((st >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask) == SHUTDOWN_crash) { cpuElem.counterBlock.host_vrt_cpu.state = SFL_VIR_DOMAIN_CRASHED; } }
/** * Reads a sampled packet header and associated information from * the buffer creates a packet sample. * Includes looking up the sampler from the ingress and egress * port information, and creating a new sampler (and poller) if * one does not already exist. */ void readPackets(HSP *sp, PUCHAR buffer) { PSFlowSample sample = (PSFlowSample)buffer; if (sample->version != 1) { myLog(LOG_INFO, "readPackets: unknown filter sample version: %u", sample->version); return; } SFL_FLOW_SAMPLE_TYPE fs = { 0 }; char *sampler_dev = NULL; uint32_t sampler_ifIndex = 0; // set the ingress and egress ifIndex numbers. // Can be "INTERNAL" (0x3FFFFFFF) or "UNKNOWN" (0). // mimic ingress sampling by using the ingress interface as the data source SFLAdaptor *in = getVAdaptorByIds(sp->vAdaptorList, sample->switchID, sample->srcPort); if (in) { fs.input = in->ifIndex; sampler_dev = in->deviceName; sampler_ifIndex = in->ifIndex; } SFLAdaptor *out = getVAdaptorByIds(sp->vAdaptorList, sample->switchID, sample->destPort); if (out) { fs.output = out->ifIndex; } else { fs.output = 0; } // must have an ifIndex to generate a sample if (sampler_ifIndex) { SFLSampler *sampler = getSampler(sp, sampler_dev, sampler_ifIndex); if (sampler) { // submit the actual sampling rate so it goes out with the sFlow feed // otherwise the sampler object would fill in his own (sub-sampling) rate. fs.sampling_rate = sample->sampleRate; // estimate the sample pool from the samples. Could maybe do this // above with the (possibly more granular) samplingRate, but then // we would have to look up the sampler object every time, which // might be too expensive in the case where samplingRate==1. sampler->samplePool += sample->sampleRate; fs.drops = sample->drops; PSFlowRecord currRecord = &sample->firstRecord; SFLFlow_sample_element hdrElem = { 0 }; SFLFlow_sample_element extSwElem = { 0 }; while (currRecord->recordType != NULL_RECORD_TYPE) { switch(currRecord->recordType) { case SAMPLED_HEADER_RECORD_TYPE: { PSFlowSampledHeader sampledHeader = GET_OPAQUE_DATA_ADDR(currRecord, PSFlowSampledHeader); hdrElem.tag = SFLFLOW_HEADER; hdrElem.flowType.header.frame_length = sampledHeader->frameLength; hdrElem.flowType.header.stripped = sampledHeader->stripped; hdrElem.flowType.header.header_protocol = SFLOW_HEADER_PROTOCOL; hdrElem.flowType.header.header_length = currRecord->dataLength - sizeof(SFlowSampledHeader); hdrElem.flowType.header.header_bytes = GET_OPAQUE_DATA_ADDR(sampledHeader, PUCHAR); SFLADD_ELEMENT(&fs, &hdrElem); if (LOG_INFO <= debug) { /*u_char pkt[HSP_MAX_HEADER_BYTES*2 +1]; //2 chars/byte + null printHex(GET_OPAQUE_DATA_ADDR(sampledHeader, PUCHAR), hdrElem.flowType.header.header_length, pkt, HSP_MAX_HEADER_BYTES*2+1, NO);*/ myLog(LOG_INFO, "readPackets: sampler: %s index: %u headerLength: %u, frameLength: %u dropped: %u", sampler->userData, SFL_DS_INDEX(sampler->dsi), hdrElem.flowType.header.header_length, hdrElem.flowType.header.frame_length, fs.drops); } break; } case EXTENDED_SWITCH_RECORD_TYPE: { PSFlowExtendedSwitch extendedSwitch = GET_OPAQUE_DATA_ADDR(currRecord, PSFlowExtendedSwitch); extSwElem.tag = SFLFLOW_EX_SWITCH; extSwElem.flowType.sw.src_vlan = extendedSwitch->sourceVLAN; extSwElem.flowType.sw.src_priority = extendedSwitch->sourcePriority; extSwElem.flowType.sw.dst_vlan = extendedSwitch->destVLAN; extSwElem.flowType.sw.dst_priority = extendedSwitch->destPriority; SFLADD_ELEMENT(&fs, &extSwElem); if (LOG_INFO <= debug) { myLog(LOG_INFO, "readPackets: sampler %s index %u srcVlan: %u srcPriority: %u dstVlan: %u dstPriority: %u", sampler->userData, SFL_DS_INDEX(sampler->dsi), extSwElem.flowType.sw.src_vlan, extSwElem.flowType.sw.src_priority, extSwElem.flowType.sw.dst_vlan, extSwElem.flowType.sw.dst_priority); } break; } case EXTENDED_TUNNEL_RECORD_TYPE: { PSFlowExtendedTunnel extendedTunnel = GET_OPAQUE_DATA_ADDR(currRecord, PSFlowExtendedTunnel); if (LOG_INFO <= debug) { myLog(LOG_INFO, "readPackets: sampler %s index %u VSID: %u", sampler->userData, SFL_DS_INDEX(sampler->dsi), extendedTunnel->vsid); } break; } default: { myLog(LOG_INFO, "readPackets: unknown filter record type: %u", currRecord->recordType); } } currRecord = GET_NEXT_SFLOW_RECORD(currRecord); } sfl_sampler_writeFlowSample(sampler, &fs); } } }