Exemple #1
0
  int readNioCounters(HSP *sp, SFLHost_nio_counters *nio, char *devFilter, SFLAdaptorList *adList) {
    int interface_count = 0;
    size_t devFilterLen = devFilter ? strlen(devFilter) : 0;

    // 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);

    for(int i = 0; i < sp->adaptorNIOList.num_adaptors; i++) {
      HSPAdaptorNIO *adaptor = sp->adaptorNIOList.adaptors[i];
      if(devFilter == NULL || !strncmp(devFilter, adaptor->deviceName, devFilterLen)) {
	if(adList == NULL || adaptorListGet(adList, adaptor->deviceName) != NULL) {
	  interface_count++;
	  // report the sum over all devices that match the filter
	  nio->bytes_in += adaptor->nio.bytes_in;
	  nio->pkts_in += adaptor->nio.pkts_in;
	  nio->errs_in += adaptor->nio.errs_in;
	  nio->drops_in += adaptor->nio.drops_in;
	  nio->bytes_out += adaptor->nio.bytes_out;
	  nio->pkts_out += adaptor->nio.pkts_out;
	  nio->errs_out += adaptor->nio.errs_out;
	  nio->drops_out += adaptor->nio.drops_out;
	}
      }
    }
    return interface_count;
  }
  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);
    }
  }
Exemple #3
0
	static SFLHost_nio_counters *getNewNIO(HSP *sp, char *deviceName) {
		// perform the same name-cleanup here as we did on the deviceName
		// in readInterfaces.  This is just in case we have the wrong list of
		// reserved characters.
		cleanNameForWMI(deviceName);
		//myLog(LOG_DEBUG, "looking up device <%s>...", deviceName);
		SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, deviceName);
		if(adaptor) {
			//myLog(LOG_DEBUG, "...found.  userData=%p", adaptor->userData);
			HSPAdaptorNIO *nio = (HSPAdaptorNIO *)adaptor->userData;
			if(nio) return &nio->new_nio;
		}
		return NULL;
	}
  void readIPv6Addresses(HSP *sp)
  {
    FILE *procFile = fopen("/proc/net/if_inet6", "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 "<address> <netlink_no> <prefix_len(HEX)> <scope(HEX)> <flags(HEX)> <deviceName>
	// (with a header line on the first row)
	char devName[MAX_PROC_LINE_CHARS];
	u_char addr[MAX_PROC_LINE_CHARS];
	u_int devNo, maskBits, scope, flags;
	++lineNo;
	if(sscanf(line, "%s %x %x %x %x %s",
		  addr,
		  &devNo,
		  &maskBits,
		  &scope,
		  &flags,
		  devName) == 6) {
	  if(debug) {
	    myLog(LOG_INFO, "adaptor %s has v6 address %s with scope 0x%x",
		  devName,
		  addr,
		  scope);
	  }
	  SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, trimWhitespace(devName));
	  if(adaptor && adaptor->userData) {
	    HSPAdaptorNIO *niostate = (HSPAdaptorNIO *)adaptor->userData;
	    SFLAddress v6addr;
	    v6addr.type = SFLADDRESSTYPE_IP_V6;
	    if(hexToBinary(addr, v6addr.address.ip_v6.addr, 16) == 16) {
	      // we interpret the scope from the address now
	      // scope = remap_proc_net_if_inet6_scope(scope);
	      EnumIPSelectionPriority ipPriority = agentAddressPriority(sp,
									&v6addr,
									niostate->vlan,
									niostate->loopback);
	      if(ipPriority > niostate->ipPriority) {
		// write this in as the preferred sflow-agent-address for this adaptor
		niostate->ipAddr = v6addr;
		niostate->ipPriority = ipPriority;
	      }
	    }
	  }
	}
      }
      fclose(procFile);
    }
  }
Exemple #5
0
  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;
  }
Exemple #6
0
  void agentCB_getCounters_interface(void *magic, SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
  {
    assert(poller->magic);
    HSP *sp = (HSP *)poller->magic;
    
    // device name was copied as userData
    char *devName = (char *)poller->userData;
    
    if(devName) {
      // look up the adaptor objects
      SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, devName);
      HSPAdaptorNIO *adaptorNIO = getAdaptorNIO(&sp->adaptorNIOList, devName);
      
      if(adaptor && adaptorNIO) {
	// make sure the counters are up to the second
	updateNioCounters(sp);
	
	// generic interface counters
	SFLCounters_sample_element elem = { 0 };
	elem.tag = SFLCOUNTERS_GENERIC;
	elem.counterBlock.generic.ifIndex = poller->dsi.ds_index;
	elem.counterBlock.generic.ifType = 6; // assume ethernet
	elem.counterBlock.generic.ifSpeed = adaptor->ifSpeed;
	elem.counterBlock.generic.ifDirection = adaptor->ifDirection;
	elem.counterBlock.generic.ifStatus = 3; // ifAdminStatus==up, ifOperstatus==up
	elem.counterBlock.generic.ifPromiscuousMode = adaptor->promiscuous;
	elem.counterBlock.generic.ifInOctets = adaptorNIO->nio.bytes_in;
	elem.counterBlock.generic.ifInUcastPkts = adaptorNIO->nio.pkts_in;
#define UNSUPPORTED_SFLOW_COUNTER32 (uint32_t)-1
	elem.counterBlock.generic.ifInMulticastPkts = UNSUPPORTED_SFLOW_COUNTER32;
	elem.counterBlock.generic.ifInBroadcastPkts = UNSUPPORTED_SFLOW_COUNTER32;
	elem.counterBlock.generic.ifInDiscards = adaptorNIO->nio.drops_in;
	elem.counterBlock.generic.ifInErrors = adaptorNIO->nio.errs_in;
	elem.counterBlock.generic.ifInUnknownProtos = UNSUPPORTED_SFLOW_COUNTER32;
	elem.counterBlock.generic.ifOutOctets = adaptorNIO->nio.bytes_out;
	elem.counterBlock.generic.ifOutUcastPkts = adaptorNIO->nio.pkts_out;
	elem.counterBlock.generic.ifOutMulticastPkts = UNSUPPORTED_SFLOW_COUNTER32;
	elem.counterBlock.generic.ifOutBroadcastPkts = UNSUPPORTED_SFLOW_COUNTER32;
	elem.counterBlock.generic.ifOutDiscards = adaptorNIO->nio.drops_out;
	elem.counterBlock.generic.ifOutErrors = adaptorNIO->nio.errs_out;
	SFLADD_ELEMENT(cs, &elem);
	sfl_poller_writeCountersSample(poller, cs);
      }
    }
  }
  int readNioCounters(HSP *sp, SFLHost_nio_counters *nio, char *devFilter, SFLAdaptorList *adList) {
    int interface_count = 0;
    size_t devFilterLen = devFilter ? strlen(devFilter) : 0;

    // 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);

    for(int i = 0; i < sp->adaptorList->num_adaptors; i++) {
      SFLAdaptor *adaptor = sp->adaptorList->adaptors[i];
      // note that the devFilter here is a prefix-match
      if(devFilter == NULL || !strncmp(devFilter, adaptor->deviceName, devFilterLen)) {
	if(adList == NULL || adaptorListGet(adList, adaptor->deviceName) != NULL) {
	  HSPAdaptorNIO *niostate = (HSPAdaptorNIO *)adaptor->userData;
	  
	  // in the case where we are adding up across all
	  // interfaces, be careful to avoid double-counting.
	  // By leaving this test until now we make it possible
	  // to know the counters for any interface or sub-interface
	  // if required (e.g. for the readPackets() module).
	  if(devFilter == NULL && (niostate->up == NO
				   || niostate->vlan != HSP_VLAN_ALL
				   || niostate->loopback
				   || niostate->bond_master)) {
	    continue;
	  }

	  interface_count++;
	  // report the sum over all devices that match the filter
	  nio->bytes_in += niostate->nio.bytes_in;
	  nio->pkts_in += niostate->nio.pkts_in;
	  nio->errs_in += niostate->nio.errs_in;
	  nio->drops_in += niostate->nio.drops_in;
	  nio->bytes_out += niostate->nio.bytes_out;
	  nio->pkts_out += niostate->nio.pkts_out;
	  nio->errs_out += niostate->nio.errs_out;
	  nio->drops_out += niostate->nio.drops_out;
	}
      }
    }
    return interface_count;
  }
Exemple #8
0
 SFLAdaptor *adaptorListAdd(SFLAdaptorList *adList, char *dev, u_char *macBytes)
 {
   SFLAdaptor *ad = adaptorListGet(adList, dev);
   if(ad == NULL) {
     ad = (SFLAdaptor *)my_calloc(sizeof(SFLAdaptor));
     ad->deviceName = strdup(dev);
   }
   if(adList->num_adaptors == adList->capacity) {
     // grow
     adList->capacity *= 2;
     adList->adaptors = (SFLAdaptor **)my_realloc(adList->adaptors, adList->capacity * sizeof(SFLAdaptor *));
   }
   adList->adaptors[adList->num_adaptors++] = ad;
   if(macBytes) {
     memcpy(ad->macs[0].mac, macBytes, 6);
     ad->num_macs = 1;
   }
   return ad;
 }
  static int containerLinkCB(void *magic, char *line) {
    HSPVMState *vm = (HSPVMState *)magic;
    if(debug) myLog(LOG_INFO, "containerLinkCB: line=<%s>", line);
    char deviceName[HSF_DOCKER_MAX_LINELEN];
    char macStr[HSF_DOCKER_MAX_LINELEN];
    uint32_t ifIndex;
    if(sscanf(line, "VNIC: %u %s %s", &ifIndex, deviceName, macStr) == 3) {
      u_char mac[6];
      if(hexToBinary((u_char *)macStr, mac, 6) == 6) {
	SFLAdaptor *adaptor = adaptorListGet(vm->interfaces, deviceName);
	if(adaptor == NULL) {
	  adaptor = adaptorListAdd(vm->interfaces, deviceName, mac, sizeof(HSPAdaptorNIO));
	}
	// set ifIndex
	adaptor->ifIndex = ifIndex;
	// clear the mark so we don't free it below
	adaptor->marked = NO;
      }
    }
    return YES;
  }
Exemple #10
0
  int readPackets(HSP *sp)
  {
    int batch = 0;
    static uint32_t MySkipCount=1;
    if(sp->sFlow->sFlowSettings->ulogSubSamplingRate == 0) {
      // packet sampling was disabled by setting desired rate to 0
      return 0;
    }
    if(sp->ulog_soc) {
      for( ; batch < HSP_READPACKET_BATCH; batch++) {
	char buf[HSP_MAX_MSG_BYTES];
	socklen_t peerlen = sizeof(sp->ulog_peer);
	int len = recvfrom(sp->ulog_soc,
			   buf,
			   HSP_MAX_MSG_BYTES,
			   0,
			   (struct sockaddr *)&sp->ulog_peer,
			   &peerlen);
	if(len <= 0) break;
	if(debug > 1) myLog(LOG_INFO, "got ULOG msg: %u bytes", len);
	for(struct nlmsghdr *msg = (struct nlmsghdr *)buf; NLMSG_OK(msg, len); msg=NLMSG_NEXT(msg, len)) {

	  if(debug > 1) {
	    myLog(LOG_INFO, "netlink (%u bytes left) msg [len=%u type=%u flags=0x%x seq=%u pid=%u]",
		  len,
		  msg->nlmsg_len,
		  msg->nlmsg_type,
		  msg->nlmsg_flags,
		  msg->nlmsg_seq,
		  msg->nlmsg_pid);
	  }

	  switch(msg->nlmsg_type) {
	  case NLMSG_NOOP:
	  case NLMSG_ERROR:
	  case NLMSG_OVERRUN:
	    // ignore these
	    break;
	  case NLMSG_DONE: // last in multi-part
	  default:
	    {

	      if(--MySkipCount == 0) {
		/* reached zero. Set the next skip */
		MySkipCount = sfl_random((2 * sp->sFlow->sFlowSettings->ulogSubSamplingRate) - 1);

		/* and take a sample */

		// we're seeing type==111 on Fedora14
		//if(msg->nlmsg_flags & NLM_F_REQUEST) { }
		//if(msg->nlmsg_flags & NLM_F_MULTI) { }
		//if(msg->nlmsg_flags & NLM_F_ACK) { }
		//if(msg->nlmsg_flags & NLM_F_ECHO) { }
		ulog_packet_msg_t *pkt = NLMSG_DATA(msg);
		
		if(debug > 1) {
		  myLog(LOG_INFO, "mark=%u ts=%s hook=%u in=%s out=%s len=%u prefix=%s maclen=%u\n",
			pkt->mark,
			ctime(&pkt->timestamp_sec),
			pkt->hook,
			pkt->indev_name,
			pkt->outdev_name,
			pkt->data_len,
			pkt->prefix,
			pkt->mac_len);
		  if(pkt->mac_len == 14) {
		    u_char macdst[12], macsrc[12];
		    printHex(pkt->mac+6,6,macsrc,12,NO);
		    printHex(pkt->mac+0,6,macdst,12,NO);
		    uint16_t ethtype = (pkt->mac[12] << 8) + pkt->mac[13];
		    myLog(LOG_INFO, "%s -> %s (ethertype=0x%04X)", macsrc, macdst, ethtype);
		  }
		}

		
		SFL_FLOW_SAMPLE_TYPE fs = { 0 };
	
		SFLSampler *sampler = NULL;

		// set the ingress and egress ifIndex numbers.
		// Can be "INTERNAL" (0x3FFFFFFF) or "UNKNOWN" (0).
		if(pkt->indev_name[0]) {
		  SFLAdaptor *in = adaptorListGet(sp->adaptorList, pkt->indev_name);
		  if(in && in->ifIndex) {
		    fs.input = in->ifIndex;
		    sampler = getSampler(sp, pkt->indev_name, in->ifIndex);
		  }
		}
		else {
		  fs.input = SFL_INTERNAL_INTERFACE;
		}
		if(pkt->outdev_name[0]) {
		  SFLAdaptor *out = adaptorListGet(sp->adaptorList, pkt->outdev_name);
		  if(out && out->ifIndex) {
		    fs.output = out->ifIndex;
		    sampler = getSampler(sp, pkt->outdev_name, out->ifIndex);
		  }
		}
		else {
		  fs.output = SFL_INTERNAL_INTERFACE;
		}

		if(sampler == NULL) {
		  // maybe ULOG sent us a packet on device lo(?)
		  if(debug > 1) myLog(LOG_INFO, "dropped sample with no ifIndex\n");
		}
		else {
		  SFLFlow_sample_element hdrElem = { 0 };
		  hdrElem.tag = SFLFLOW_HEADER;
		  uint32_t FCS_bytes = 4;
		  uint32_t maxHdrLen = sampler->sFlowFsMaximumHeaderSize;
		  hdrElem.flowType.header.frame_length = pkt->data_len + FCS_bytes;
		  hdrElem.flowType.header.stripped = FCS_bytes;
		
		  u_char hdr[HSP_MAX_HEADER_BYTES];
		
		  if(pkt->mac_len == 14) {
		    // set the header_protocol to ethernet and
		    // reunite the mac header and payload in one buffer
		    hdrElem.flowType.header.header_protocol = SFLHEADER_ETHERNET_ISO8023;
		    memcpy(hdr, pkt->mac, 14);
		    maxHdrLen -= 14;
		    uint32_t payloadBytes = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
		    memcpy(hdr+14, pkt->payload, payloadBytes);
		    hdrElem.flowType.header.header_length = payloadBytes + 14;
		    hdrElem.flowType.header.header_bytes = hdr;
		    hdrElem.flowType.header.frame_length += 14;
		  }
		  else {
		    // no need to copy - just point at the payload
		    u_char ipversion = pkt->payload[0] >> 4;
		    if(ipversion != 4 && ipversion != 6) {
		      if(debug) myLog(LOG_ERR, "received non-IP packet. Encapsulation is unknown");
		    }
		    else {
		      hdrElem.flowType.header.header_protocol = (ipversion == 4) ? SFLHEADER_IPv4 : SFLHEADER_IPv6;
		      hdrElem.flowType.header.stripped += 14; // assume ethernet was (or will be) the framing
		      hdrElem.flowType.header.header_length = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
		      hdrElem.flowType.header.header_bytes = pkt->payload;
		    }
		  }
		
		  SFLADD_ELEMENT(&fs, &hdrElem);
		  // 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.
		  uint32_t actualSamplingRate = sp->sFlow->sFlowSettings->ulogActualSamplingRate;
		  fs.sampling_rate = actualSamplingRate;

		  // estimate the sample pool from the samples.  Could maybe do this
		  // above with the (possibly more granular) ulogSamplingRate, but then
		  // we would have to look up the sampler object every time, which
		  // might be too expensive in the case where ulogSamplingRate==1.
		  sampler->samplePool += actualSamplingRate;

		  sfl_sampler_writeFlowSample(sampler, &fs);
		}
	      }
	    }
	  } 
	}
      }
    }
/**
 * Gets the switch port info from WMI (switch port friendly name, ifSpeed) 
 * and merges into the list of existing ports.
 */
void readWMISwitchPorts(HSP *sp)
{
	BSTR path = SysAllocString(WMI_VIRTUALIZATION_NS_V2);
	HRESULT hr = S_FALSE;
	IWbemServices *pNamespace = NULL;

	hr = connectToWMI(path, &pNamespace);
	if (FAILED(hr)) {
		//only try the v2 namespace since this will only be present
		//with the extensible switch that supports sampling.
	    //don't try to get counters if there is no sampling.
		SysFreeString(path);
		myLog(LOG_INFO, "readWMISwitchPorts: virtualization namespace v2 not found");
		return;
	} else {
		SysFreeString(path);
	}

	BSTR queryLang = SysAllocString(L"WQL");
	wchar_t *query = L"SELECT * FROM Msvm_EthernetSwitchPort";
	IEnumWbemClassObject *switchPortEnum = NULL;
	hr = pNamespace->ExecQuery(queryLang, query, WBEM_FLAG_FORWARD_ONLY, NULL, &switchPortEnum);
	SysFreeString(queryLang);
	if (FAILED(hr)) {
		myLog(LOG_ERR,"readWMISwitchPorts: ExecQuery() failed for query %S error=0x%x", query, hr);
		pNamespace->Release();
		return;
	}

	if (sp->vAdaptorList == NULL) {
		sp->vAdaptorList = adaptorListNew();
	}
	IWbemClassObject *switchPortObj = NULL;

	hr = WBEM_S_NO_ERROR;
	while (WBEM_S_NO_ERROR == hr) {
		SFLAdaptor *vAdaptor = NULL;
		ULONG uReturned = 1;
		hr = switchPortEnum->Next(WBEM_INFINITE, 1, &switchPortObj, &uReturned);
		if (0 == uReturned) {
			break;
		}
		wchar_t *guidString = stringFromWMIProperty(switchPortObj, PROP_NAME);
		if (guidString != NULL) {
			char portGuid[FORMATTED_GUID_LEN+1];
			guidToString(guidString, (UCHAR *)portGuid, FORMATTED_GUID_LEN);
			myLog(LOG_INFO, "readWMISwitchPorts: portGuid=%s", portGuid);
			my_free(guidString);
			vAdaptor = adaptorListGet(sp->vAdaptorList, portGuid);
		}
		if (vAdaptor != NULL) {
			HVSVPortInfo *portInfo = (HVSVPortInfo *)vAdaptor->userData;
			wchar_t *switchName = stringFromWMIProperty(switchPortObj, PROP_SYSTEM_NAME);
			if (switchName != NULL) {
				if (portInfo->switchName != NULL) {
					my_free(portInfo->switchName);
				}
				portInfo->switchName = switchName;
			}
			wchar_t *friendlyName = stringFromWMIProperty(switchPortObj, PROP_ELEMENT_NAME);
			if (friendlyName != NULL) {
				if (portInfo->portFriendlyName != NULL) {
					my_free(portInfo->portFriendlyName);
				}
				portInfo->portFriendlyName = friendlyName;
			}
			setPortCountersInstance(vAdaptor);
			wchar_t *speedString = stringFromWMIProperty(switchPortObj, PROP_SPEED);
			if (speedString != NULL) {
				ULONGLONG ifSpeed = _wcstoui64(speedString, NULL, 10);
				vAdaptor->ifSpeed = ifSpeed;
				my_free(speedString);
			}
			//could also get ifDirection but FullDuplex=True always

			//Get the MACs and VM system name when we enumerate the vms.
			myLog(LOG_INFO, 
				  "readWMISwitchPorts: updated switch port %s %S portId=%u ifIndex=%u ifSpeed=%llu counterName=%S", 
				  vAdaptor->deviceName, portInfo->portFriendlyName, portInfo->portId, vAdaptor->ifIndex, 
				  vAdaptor->ifSpeed, portInfo->portCountersInstance);
		} else {
			myLog(LOG_INFO, "readWMISwitchPorts: vAdapter not found");
		}
		switchPortObj->Release();
	}
	switchPortEnum->Release();
	pNamespace->Release();
}
/**
 * Updates the switch port list with the information in pSwitchConfig
 * obtained from the filter.
 */
void updateSwitchPorts(HSP *sp, PAllSwitchesConfig config)
{
	if (config->revision <= sp->portInfoRevision) {
		return;
	}
	if (sp->vAdaptorList == NULL) {
		sp->vAdaptorList = adaptorListNew();
	} else {
		adaptorListMarkAll(sp->vAdaptorList);
	}
	PSwitchConfig switchConfig;
	for (uint32_t switchNum = 0; switchNum < config->numSwitches; switchNum++) {
		if (switchNum == 0) {
			switchConfig = GET_FIRST_SWITCH_CONFIG(config);
		} else {
			switchConfig = GET_NEXT_SWITCH_CONFIG(switchConfig);
		}
		wchar_t *switchName = ndiswcsdup(&switchConfig->switchName);
		uint64_t switchId = switchConfig->switchID;
		for (uint32_t portNum = 0; portNum < switchConfig->numPorts; portNum++) {
			PPortEntry portEntry = GET_PORT_ENTRY_AT(switchConfig, portNum);
			uint32_t portId = portEntry->portID;
			wchar_t *portName = ndiswcsdup(&portEntry->portName);
			char portGuid[FORMATTED_GUID_LEN+1];
			guidToString(portName, (UCHAR *)portGuid, FORMATTED_GUID_LEN);
			SFLAdaptor *switchPort = adaptorListGet(sp->vAdaptorList, portGuid);
			if (switchPort == NULL) {
				//new port so add to the vadaptor list
				//convert GUID to uuid format to look up ifIndex/dsIndex
				char uuid[16];
				hexToBinary((UCHAR *)portGuid, (UCHAR *)uuid, 33);
				uint32_t ifIndex = assign_dsIndex(&sp->portStore, uuid, &sp->maxIfIndex, &sp->portStoreInvalid);
				switchPort = addVAdaptor(sp->vAdaptorList, portGuid, ifIndex);
				HVSVPortInfo *portInfo = (HVSVPortInfo *)switchPort->userData;
				portInfo->filterEnabled = TRUE;
				portInfo->portId = portId;
				portInfo->revision = portEntry->revision;
				switchPort->marked = FALSE;
				updatePortSwitchName(switchPort, switchName);
				portInfo->switchId = switchConfig->switchID;
				myLog(LOG_INFO, "updateSwitchPorts: Added new portId=%u ifIndex=%u deviceName=%s switchId=%llu switchName=%S",
					portInfo->portId, switchPort->ifIndex, switchPort->deviceName, portInfo->switchId, portInfo->switchName);
				addPoller(sp, switchPort);
			} else {
				//we already know about this port, so make sure we have a poller
				//and the current info
				SFLDataSource_instance dsi;
				SFL_DS_SET(dsi, 0, switchPort->ifIndex, 0);
				SFLPoller *poller = sfl_agent_getPoller(sp->sFlow->agent, &dsi);
				if (poller == NULL) {
					poller = addPoller(sp, switchPort);
				}
				HVSVPortInfo *portInfo = (HVSVPortInfo *)switchPort->userData;
				if (portEntry->revision > portInfo->revision) {
					updatePortSwitchName(switchPort, switchName);
					portInfo->revision = portEntry->revision;
					if (poller != NULL) {
						sfl_poller_resetCountersSeqNo(poller);
					}
					myLog(LOG_INFO, "updateSwitchPorts: revision changed: portId=%u ifIndex=%u deviceName=%s switchId=%llu switchName=%S", 
						  portInfo->portId, switchPort->ifIndex, switchPort->deviceName, portInfo->switchId, portInfo->switchName);
				}
				portInfo->filterEnabled = TRUE;
				switchPort->marked = FALSE;
			}
			my_free(portName);
		}
		my_free(switchName);
	}
	//now sweep
	//remove the pollers for non-sampling ports
	for (uint32_t i = 0; i < sp->vAdaptorList->num_adaptors; i++) {
		SFLAdaptor *vAdaptor = sp->vAdaptorList->adaptors[i];
		if (vAdaptor->marked) {
			HVSVPortInfo *portInfo = (HVSVPortInfo *)vAdaptor->userData;
			if (portInfo->filterEnabled) {
				//filter (ie sampling) has been disabled in the switch with this port
				((HVSVPortInfo *)vAdaptor->userData)->portId = 0;
				removePoller(sp, vAdaptor);
				portInfo->filterEnabled = FALSE;
				//Clear the mark so this port will not be deleted, the VM and adaptor may still exist.
				//If the adaptor does not exist, it will be removed when we next refresh the VMs.
				vAdaptor->marked = FALSE;
			} else {
				//this was a port added for a vm on a switch with the filter disabled, so
				//just clear the mark so that it will not be deleted.
				vAdaptor->marked = FALSE;
			}	
		}
	}
	//Now remove the marked adaptors and their port info from the list
	adaptorListFreeMarked(sp->vAdaptorList, freePortInfo);
	//TODO ageout the persistent ifIndex->GUID mapping and remove from vAdaptor list.
	sp->portInfoRevision = config->revision;
	readWMISwitchPorts(sp); //update the ifSpeed, MAC, VM name
	sp->refreshVms = TRUE;
}
  int readInterfaces(HSP *sp, uint32_t *p_added, uint32_t *p_removed, uint32_t *p_cameup, uint32_t *p_wentdown, uint32_t *p_changed)
{
  uint32_t ad_added=0, ad_removed=0, ad_cameup=0, ad_wentdown=0, ad_changed=0;
  if(sp->adaptorList == NULL) sp->adaptorList = adaptorListNew();
  else adaptorListMarkAll(sp->adaptorList);

  // Walk the interfaces and collect the non-loopback interfaces so that we
  // have a list of MAC addresses for each interface (usually only 1).
  //
  // May need to come back and run a variation of this where we supply
  // a domain and collect the virtual interfaces for that domain in a
  // similar way.  It looks like we do that by just parsing the numbers
  // out of the interface name.
  
  int fd = socket (PF_INET, SOCK_DGRAM, 0);
  if (fd < 0) {
    fprintf (stderr, "error opening socket: %d (%s)\n", errno, strerror(errno));
    return 0;
  }

  FILE *procFile = fopen("/proc/net/dev", "r");
  if(procFile) {
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    char line[MAX_PROC_LINE_CHARS];
    int lineNo = 0;
    while(fgets(line, MAX_PROC_LINE_CHARS, procFile)) {
      if(lineNo++ < 2) continue; // skip headers
      // the device name is always the first token before the ":"
      char buf[MAX_PROC_LINE_CHARS];
      char *p = line;
      char *devName = parseNextTok(&p, " \t:", NO, '\0', NO, buf, MAX_PROC_LINE_CHARS);
      if(devName && my_strlen(devName) < IFNAMSIZ) {
	devName = trimWhitespace(devName);
	if(devName && strlen(devName) < IFNAMSIZ) {
	  // we set the ifr_name field to make our queries
	  strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));

	  if(debug > 1) {
	    myLog(LOG_INFO, "reading interface %s", devName);
	  }

	  // Get the flags for this interface
	  if(ioctl(fd,SIOCGIFFLAGS, &ifr) < 0) {
	    myLog(LOG_ERR, "device %s Get SIOCGIFFLAGS failed : %s",
		  devName,
		  strerror(errno));
	  }
	  else {
	    int up = (ifr.ifr_flags & IFF_UP) ? YES : NO;
	    int loopback = (ifr.ifr_flags & IFF_LOOPBACK) ? YES : NO;
	    int promisc =  (ifr.ifr_flags & IFF_PROMISC) ? YES : NO;
	    int bond_master = (ifr.ifr_flags & IFF_MASTER) ? YES : NO;
	    int bond_slave = (ifr.ifr_flags & IFF_SLAVE) ? YES : NO;
	    //int hasBroadcast = (ifr.ifr_flags & IFF_BROADCAST);
	    //int pointToPoint = (ifr.ifr_flags & IFF_POINTOPOINT);

	    // used to ignore loopback interfaces here, and interfaces
	    // that are currently marked down, but now those are
	    // filtered at the point where we roll together the
	    // counters, or build the list for export
	      
	    // Get the MAC Address for this interface
	    if(ioctl(fd,SIOCGIFHWADDR, &ifr) < 0) {
	      myLog(LOG_ERR, "device %s Get SIOCGIFHWADDR failed : %s",
		    devName,
		    strerror(errno));
	    }
	    
	    // for now just assume that each interface has only one MAC.  It's not clear how we can
	    // learn multiple MACs this way anyhow.  It seems like there is just one per ifr record.
	    // find or create a new "adaptor" entry
	    SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, devName);
	    if(adaptor == NULL) {
	      ad_added++;
	      adaptor = adaptorListAdd(sp->adaptorList, devName, (u_char *)&ifr.ifr_hwaddr.sa_data, sizeof(HSPAdaptorNIO));
	    }
	    
	    // clear the mark so we don't free it below
	    adaptor->marked = NO;
	    
	    // this flag might belong in the adaptorNIO struct
	    adaptor->promiscuous = promisc;
	    
	    // remember some useful flags in the userData structure
	    HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)adaptor->userData;
	    if(adaptorNIO->up != up) {
	      if(up) ad_cameup++;
	      else ad_wentdown++;
	      if(debug) {
		myLog(LOG_INFO, "adaptor %s %s",
		      adaptor->deviceName,
		      up ? "came up" : "went down");
	      }
	    }
	    adaptorNIO->up = up;
	    adaptorNIO->loopback = loopback;
	    adaptorNIO->bond_master = bond_master;
	    adaptorNIO->bond_slave = bond_slave;
	    adaptorNIO->vlan = HSP_VLAN_ALL; // may be modified below
#ifdef HSP_SWITCHPORT_REGEX
	    if(regexec(&sp->swp_regex, devName, 0, NULL, 0) == 0) {
	      adaptorNIO->switchPort = YES;
	    }
#endif
	    // Try and get the ifIndex for this interface
	    if(ioctl(fd,SIOCGIFINDEX, &ifr) < 0) {
	      // only complain about this if we are debugging
	      if(debug) {
		myLog(LOG_ERR, "device %s Get SIOCGIFINDEX failed : %s",
		      devName,
		      strerror(errno));
	      }
	    }
	    else {
	      adaptor->ifIndex = ifr.ifr_ifindex;
	    }
	    
	    // Try to get the IP address for this interface
	    if(ioctl(fd,SIOCGIFADDR, &ifr) < 0) {
	      // only complain about this if we are debugging
	      if(debug) {
		myLog(LOG_ERR, "device %s Get SIOCGIFADDR failed : %s",
		      devName,
		      strerror(errno));
	      }
	    }
	    else {
	      if (ifr.ifr_addr.sa_family == AF_INET) {
		struct sockaddr_in *s = (struct sockaddr_in *)&ifr.ifr_addr;
		// IP addr is now s->sin_addr
		adaptorNIO->ipAddr.type = SFLADDRESSTYPE_IP_V4;
		adaptorNIO->ipAddr.address.ip_v4.addr = s->sin_addr.s_addr;
	      }
	      //else if (ifr.ifr_addr.sa_family == AF_INET6) {
	      // not sure this ever happens - on a linux system IPv6 addresses
	      // are picked up from /proc/net/if_inet6
	      // struct sockaddr_in6 *s = (struct sockaddr_in6 *)&ifr.ifr_addr;
	      // IP6 addr is now s->sin6_addr;
	      //}
	    }

	    // use ethtool to get info about direction/speed and more
	    if(read_ethtool_info(&ifr, fd, adaptor) == YES) {
	      ad_changed++;
	    }
	  }
	}
      }
    }
    fclose(procFile);
  }
  
  close (fd);

  // now remove and free any that are still marked
  ad_removed = adaptorListFreeMarked(sp->adaptorList);

  // check in case any of the survivors are specific
  // to a particular VLAN
  readVLANs(sp);

  // now that we have the evidence gathered together, we can
  // set the L3 address priorities (used for auto-selecting
  // the sFlow-agent-address if requrired to by the config.
  setAddressPriorities(sp);

  // now we can read IPv6 addresses too - they come from a
  // different place. Depending on the address priorities this
  // may cause the adaptor's best-choice ipAddress to be
  // overwritten.
  readIPv6Addresses(sp);

  if(p_added) *p_added = ad_added;
  if(p_removed) *p_removed = ad_removed;
  if(p_cameup) *p_cameup = ad_cameup;
  if(p_wentdown) *p_wentdown = ad_wentdown;
  if(p_changed) *p_changed = ad_changed;

  return sp->adaptorList->num_adaptors;
}
Exemple #14
0
  int HSPReadConfigFile(HSP *sp)
  {
    EnumHSPObject level[HSP_MAX_CONFIG_DEPTH + 5];
    int depth = 0;
    level[depth] = HSPOBJ_HSP;

    // could have used something like bison to make a complete parser with
    // strict rules,  but for simplicity we just allow the current object
    // to double as a state variable that determines what is allowed next.
    
    for(HSPToken *tok = readTokens(sp); tok; tok = tok->nxt) {

      if(depth > HSP_MAX_CONFIG_DEPTH) {
	// depth overrun
	parseError(sp, tok, "too many '{'s", "");
	return NO;
      }
      else if(tok->stok == HSPTOKEN_ENDOBJ) {
	// end of level, pop the stack
	if(depth > 0) --depth;
	else {
	  parseError(sp, tok, "too many '}'s ", "");
	  return NO;
	}
      }
      else switch(level[depth]) {
      case HSPOBJ_HSP:
	// must start by opening an sFlow object
	if((tok = expectToken(sp, tok, HSPTOKEN_SFLOW)) == NULL) return NO;
	if((tok = expectToken(sp, tok, HSPTOKEN_STARTOBJ)) == NULL) return NO;
	newSFlow(sp);
	level[++depth] = HSPOBJ_SFLOW;
	break;

      case HSPOBJ_SFLOW:

	switch(tok->stok) {
	case HSPTOKEN_DNSSD:
	  if((tok = expectDNSSD(sp, tok)) == NULL) return NO;
	  break;
	case HSPTOKEN_DNSSD_DOMAIN:
	  if((tok = expectDNSSD_domain(sp, tok)) == NULL) return NO;
	  break;
	case HSPTOKEN_COLLECTOR:
	  if((tok = expectToken(sp, tok, HSPTOKEN_STARTOBJ)) == NULL) return NO;
	  newCollector(sp->sFlow->sFlowSettings_file);
	  level[++depth] = HSPOBJ_COLLECTOR;
	  break;
	case HSPTOKEN_SAMPLING:
	case HSPTOKEN_PACKETSAMPLINGRATE:
	  if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->samplingRate, 0, 65535)) == NULL) return NO;
	  break;
	case HSPTOKEN_POLLING:
	case HSPTOKEN_COUNTERPOLLINGINTERVAL:
	  if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->pollingInterval, 0, 300)) == NULL) return NO;
	  break;
	case HSPTOKEN_AGENTIP:
	  if((tok = expectIP(sp, tok, &sp->sFlow->agentIP, NULL)) == NULL) return NO;
	  break;
	case HSPTOKEN_AGENT:
	  if((tok = expectDevice(sp, tok, &sp->sFlow->agentDevice)) == NULL) return NO;
	  break;
	case HSPTOKEN_SUBAGENTID:
	  if((tok = expectInteger32(sp, tok, &sp->sFlow->subAgentId, 0, HSP_MAX_SUBAGENTID)) == NULL) return NO;
	  break;
	case HSPTOKEN_UUID:
	  if((tok = expectUUID(sp, tok, sp->uuid)) == NULL) return NO;
	  break;
	case HSPTOKEN_HEADERBYTES:
	  if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->headerBytes, 0, HSP_MAX_HEADER_BYTES)) == NULL) return NO;
	  break;
	case HSPTOKEN_ULOGGROUP:
	  if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->ulogGroup, 1, 32)) == NULL) return NO;
	  break;
	case HSPTOKEN_ULOGPROBABILITY:
	  if((tok = expectDouble(sp, tok, &sp->sFlow->sFlowSettings_file->ulogProbability, 0.0, 1.0)) == NULL) return NO;
	  break;
	default:
	  parseError(sp, tok, "unexpected sFlow setting", "");
	  return NO;
	  break;
	}
	break;
	
      case HSPOBJ_COLLECTOR:
	{
	  HSPCollector *col = sp->sFlow->sFlowSettings_file->collectors;
	  switch(tok->stok) {
	  case HSPTOKEN_IP:
	    if((tok = expectIP(sp, tok, &col->ipAddr, (struct sockaddr *)&col->sendSocketAddr)) == NULL) return NO;
	    break;
	  case HSPTOKEN_UDPPORT:
	    if((tok = expectInteger32(sp, tok, &col->udpPort, 1, 65535)) == NULL) return NO;
	    break;
	  default:
	    parseError(sp, tok, "unexpected collector setting", "");
	    return NO;
	    break;
	  }
	}
	break;
	
      default:
	parseError(sp, tok, "unexpected state", "");
      }
    }

    // OK we consumed all the tokens, but we still need to run some sanity checks to make sure
    // we have a usable configuration...

    int parseOK = YES;

    if(sp->sFlow == NULL) {
      myLog(LOG_ERR, "parse error in %s : sFlow not found", sp->configFile);
      parseOK = NO;
    }
    else {
      //////////////////////// sFlow /////////////////////////
      if(sp->sFlow->agentIP.type == 0) {
	 // it may have been defined as agent=<device>
	if(sp->sFlow->agentDevice) {
	  SFLAdaptor *ad = adaptorListGet(sp->adaptorList, sp->sFlow->agentDevice);
	  if(ad && ad->ipAddr.addr) {
	    sp->sFlow->agentIP.type = SFLADDRESSTYPE_IP_V4;
	    sp->sFlow->agentIP.address.ip_v4 = ad->ipAddr;
	  }
	}
      }
      if(sp->sFlow->agentIP.type == 0) {
	 // nae luck - try to automatically choose the first non-loopback IP address
	 for(uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) {
	    SFLAdaptor *adaptor = sp->adaptorList->adaptors[i];
	    // only the non-loopback devices should be listed here, so just take the first
	    if(adaptor && adaptor->ipAddr.addr) {
	       sp->sFlow->agentIP.type = SFLADDRESSTYPE_IP_V4;
	       sp->sFlow->agentIP.address.ip_v4 = adaptor->ipAddr;
	       // fill in the device that we picked too
	       sp->sFlow->agentDevice = strdup(adaptor->deviceName);
	       break;
	    }
	 }
      }

      if(sp->sFlow->agentIP.type == SFLADDRESSTYPE_IP_V4 && sp->sFlow->agentDevice == NULL) {
	// try to fill in the device field too (because we need to give that one to open vswitch).
	for(uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) {
	  SFLAdaptor *adaptor = sp->adaptorList->adaptors[i];
	  if(adaptor && (adaptor->ipAddr.addr == sp->sFlow->agentIP.address.ip_v4.addr)) {
	    sp->sFlow->agentDevice = strdup(adaptor->deviceName);
	    break;
	  }
	}
      }

      if(sp->sFlow->agentIP.type == 0) {
        // still no agentIP.  That's a showstopper.
	myLog(LOG_ERR, "parse error in %s : agentIP not defined", sp->configFile);
	parseOK = NO;
      }
      if(sp->sFlow->sFlowSettings_file->numCollectors == 0 && sp->DNSSD == NO) {
	myLog(LOG_ERR, "parse error in %s : DNS-SD is off and no collectors are defined", sp->configFile);
	parseOK = NO;
      }
      for(HSPCollector *coll = sp->sFlow->sFlowSettings_file->collectors; coll; coll = coll->nxt) {
	//////////////////////// collector /////////////////////////
	if(coll->ipAddr.type == 0) {
	  myLog(LOG_ERR, "parse error in %s : collector  has no IP", sp->configFile);
	  parseOK = NO;
	}
      }

      if(sp->sFlow->sFlowSettings_file->ulogProbability > 0) {
	sp->sFlow->sFlowSettings_file->ulogSamplingRate = (uint32_t)(1.0 / sp->sFlow->sFlowSettings_file->ulogProbability);
      }

    }

    return parseOK;
  }
Exemple #15
0
/**
 * Gets the switch port info from WMI (switch port friendly name, ifSpeed) 
 * and merges into the list of existing ports.
 */
void readWMISwitchPorts(HSP *sp)
{
	myLog(LOG_INFO, "entering readWMISwitchPorts");
	BSTR path = SysAllocString(WMI_VIRTUALIZATION_NS_V2);
	HRESULT hr = S_FALSE;
	IWbemServices *pNamespace = NULL;

	hr = connectToWMI(path, &pNamespace);
	if (FAILED(hr)) {
		//only try the v2 namespace since this will only be present
		//with the extensible switch that supports sampling.
	    //don't try to get counters if there is no sampling.
		SysFreeString(path);
		myLog(LOG_INFO, "readWMISwitchPorts: virtualization namespace v2 not found");
		return;
	} else {
		SysFreeString(path);
	}

	BSTR queryLang = SysAllocString(L"WQL");
	BSTR query = SysAllocString(L"SELECT * FROM Msvm_EthernetSwitchPort");
	IEnumWbemClassObject *switchPortEnum = NULL;
	hr = pNamespace->ExecQuery(queryLang, query, WBEM_FLAG_FORWARD_ONLY, NULL, &switchPortEnum);
	SysFreeString(queryLang);
	SysFreeString(query);
	if (FAILED(hr)) {
		myLog(LOG_ERR,"readWMISwitchPorts: ExecQuery() failed for query %S error=0x%x", query, hr);
		CoUninitialize();
		return;
	}

	if (sp->vAdaptorList == NULL) {
		sp->vAdaptorList = adaptorListNew();
	}
	IWbemClassObject *switchPortObj = NULL;

	BSTR propElementName = SysAllocString(L"ElementName");
	BSTR propSystemName = SysAllocString(L"SystemName");
	BSTR propName = SysAllocString(L"Name");
	BSTR propSpeed = SysAllocString(L"Speed");
	//could also get ifDirection but FullDuplex=True always
	VARIANT systemVal;
	VARIANT elementVal;
	VARIANT nameVal;
	VARIANT speedVal;

	hr = WBEM_S_NO_ERROR;
	while (WBEM_S_NO_ERROR == hr) {
		SFLAdaptor *vAdaptor = NULL;
		ULONG uReturned = 1;
		hr = switchPortEnum->Next(WBEM_INFINITE, 1, &switchPortObj, &uReturned);
		if (0 == uReturned) {
			break;
		}
		HRESULT portHr;
		portHr = switchPortObj->Get(propName, 0, &nameVal, 0, 0);
		char portGuid[FORMATTED_GUID_LEN+1];
		guidToString(nameVal.bstrVal, (UCHAR *)portGuid, FORMATTED_GUID_LEN);
		myLog(LOG_INFO, "readWMISwitchPorts: portGuid=%s", portGuid);
		VariantClear(&nameVal);
		vAdaptor = adaptorListGet(sp->vAdaptorList, portGuid);
		if (vAdaptor != NULL) {
			portHr = switchPortObj->Get(propSystemName, 0, &systemVal, 0, 0);
			portHr = switchPortObj->Get(propElementName, 0, &elementVal, 0, 0);
			portHr = switchPortObj->Get(propSpeed, 0, &speedVal, 0, 0);
			int length = SysStringLen(systemVal.bstrVal)+1; //include room for terminating null
			wchar_t *switchName = (wchar_t *)my_calloc(length*sizeof(wchar_t));
			wcscpy_s(switchName, length, systemVal.bstrVal);
			length = SysStringLen(elementVal.bstrVal)+1; 
			wchar_t *friendlyName = (wchar_t *)my_calloc(length*sizeof(wchar_t));
			wcscpy_s(friendlyName, length, elementVal.bstrVal);
			ULONGLONG ifSpeed = _wcstoui64(speedVal.bstrVal, NULL, 10);
			VariantClear(&systemVal);
			VariantClear(&elementVal);
			VariantClear(&speedVal);
			HVSVPortInfo *portInfo = (HVSVPortInfo *)vAdaptor->userData;
			if (portInfo->switchName != NULL) {
				my_free(portInfo->switchName);
			}
			portInfo->switchName = switchName;
			if (portInfo->portFriendlyName != NULL) {
				my_free(portInfo->portFriendlyName);
			}
			portInfo->portFriendlyName = friendlyName;
			setPortCountersInstance(vAdaptor);
			vAdaptor->ifSpeed = ifSpeed;
			//Get the MACs and VM system name when we enumerate the vms.
			myLog(LOG_INFO, 
				  "readWMISwitchPorts: updated switch port %s %S portId=%u ifIndex=%u ifSpeed=%llu counterName=%S", 
				  vAdaptor->deviceName, portInfo->portFriendlyName, portInfo->portId, vAdaptor->ifIndex, 
				  vAdaptor->ifSpeed, portInfo->portCountersInstance);
		} else {
			myLog(LOG_INFO, "readWMISwitchPorts: vAdapter not found");
		}
		switchPortObj->Release();
	}
	switchPortEnum->Release();
	pNamespace->Release();
	CoUninitialize();
	SysFreeString(propElementName);
	SysFreeString(propSystemName);
	SysFreeString(propName);
	SysFreeString(propSpeed);

	return;
}
  void updateBondCounters(HSP *sp, SFLAdaptor *bond) {
    char procFileName[256];
    snprintf(procFileName, 256, "/proc/net/bonding/%s", bond->deviceName);
    FILE *procFile = fopen(procFileName, "r");
    if(procFile) {
      // 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];
      SFLAdaptor *currentSlave = NULL;
      HSPAdaptorNIO *slave_nio = NULL;
      HSPAdaptorNIO *bond_nio = (HSPAdaptorNIO *)bond->userData;
      HSPAdaptorNIO *aggregator_slave_nio = NULL;
      bond_nio->lacp.attachedAggID = bond->ifIndex;
      uint32_t aggID = 0;
      // make sure we don't hold on to stale data - may need
      // to pick up actorSystemID from a slave port.
      memset(bond_nio->lacp.actorSystemID, 0, 6);
      memset(bond_nio->lacp.partnerSystemID, 0, 6);
      int readingMaster = YES; // bond master data comes first
      int gotActorID = NO;
      while(fgets(line, MAX_PROC_LINE_CHARS, procFile)) {
	char buf_var[MAX_PROC_LINE_CHARS];
	char buf_val[MAX_PROC_LINE_CHARS];
	// buf_var is up to first ':', buf_val is the rest
	if(sscanf(line, "%[^:]:%[^\n]", buf_var, buf_val) == 2) {
	  char *tok_var = trimWhitespace(buf_var);
	  char *tok_val = trimWhitespace(buf_val);
	  
	  if(readingMaster) {
	    if(my_strequal(tok_var, "MII Status")) {
	      if(my_strequal(tok_val, "up")) {
		bond_nio->lacp.portState.v.actorAdmin = 2; // dot3adAggPortActorAdminState
		bond_nio->lacp.portState.v.actorOper = 2;
		bond_nio->lacp.portState.v.partnerAdmin = 2;
		bond_nio->lacp.portState.v.partnerOper = 2;
	      }
	      else {
		bond_nio->lacp.portState.all = 0;
	      }
	    }
	    
	    if(my_strequal(tok_var, "System Identification")) {
	      if(debug) {
		myLog(LOG_INFO, "updateBondCounters: %s system identification %s",
		      bond->deviceName,
		      tok_val);
	      }
	      char sys_mac[MAX_PROC_LINE_CHARS];
	      uint64_t code;
	      if(sscanf(tok_val, "%"SCNu64"  %s", &code, sys_mac) == 2) {
		if(hexToBinary((u_char *)sys_mac,bond_nio->lacp.actorSystemID, 6) != 6) {
		  myLog(LOG_ERR, "updateBondCounters: system mac read error: %s", sys_mac);
		}
		else if(!isAllZero(bond_nio->lacp.actorSystemID, 6)) {
		  gotActorID = YES;
		}
	      }
	    }
	    
	    if(my_strequal(tok_var, "Partner Mac Address")) {
	      if(debug) {
		myLog(LOG_INFO, "updateBondCounters: %s partner mac is %s",
		      bond->deviceName,
		      tok_val);
	      }
	      if(hexToBinary((u_char *)tok_val,bond_nio->lacp.partnerSystemID, 6) != 6) {
		myLog(LOG_ERR, "updateBondCounters: partner mac read error: %s", tok_val);
	      }
	    }
	    
	    if(my_strequal(tok_var, "Aggregator ID")) {
	      aggID = strtol(tok_val, NULL, 0);
	      if(debug) {
		myLog(LOG_INFO, "updateBondCounters: %s aggID %u", bond->deviceName, aggID);
	      }
	    }
	  }
	  
	  // initially the data is for the bond, but subsequently
	  // we get info about each slave. So we started with
	  // (readingMaster=YES,currentSlave=NULL), and now we
	  // detect transitions to slave data:
	  if(my_strequal(tok_var, "Slave Interface")) {
	    readingMaster = NO;
	    currentSlave = adaptorListGet(sp->adaptorList, trimWhitespace(tok_val));
	    slave_nio = currentSlave ? (HSPAdaptorNIO *)currentSlave->userData : NULL;
	    if(debug) {
	      myLog(LOG_INFO, "updateBondCounters: bond %s slave %s %s",
		    bond->deviceName,
		    tok_val,
		    currentSlave ? "found" : "not found");
	    }
	    if(slave_nio) {
	      // initialize from bond
	      slave_nio->lacp.attachedAggID = bond->ifIndex;
	      memcpy(slave_nio->lacp.partnerSystemID, bond_nio->lacp.partnerSystemID, 6);
	      memcpy(slave_nio->lacp.actorSystemID, bond_nio->lacp.actorSystemID, 6);
	      
	      // make sure the parent is going to export separate
	      // counters if the slave is going to (because it was
	      // marked as a switchPort):
	      if(slave_nio->switchPort) {
		bond_nio->switchPort = YES;
	      }
	      // and vice-versa
	      if(bond_nio->switchPort) {
		slave_nio->switchPort = YES;
	      }
	    }
	  }
	  
	  if(readingMaster == NO && slave_nio) {
	    if(my_strequal(tok_var, "MII Status")) {
	      if(my_strequal(tok_val, "up")) {
		slave_nio->lacp.portState.v.actorAdmin = 2; // dot3adAggPortActorAdminState
		slave_nio->lacp.portState.v.actorOper = 2;
		slave_nio->lacp.portState.v.partnerAdmin = 2;
		slave_nio->lacp.portState.v.partnerOper = 2;
	      }
	      else {
		slave_nio->lacp.portState.all = 0;
	      }
	    }
	    
	    if(my_strequal(tok_var, "Permanent HW addr")) {
	      if(!gotActorID) {
		// Still looking for our actorSystemID, so capture this here in case we
		// decide below that it is the one we want.  Note that this mac may not be the
		// same as the mac associated with this port that we read back in readInterfaces.c.
		if(hexToBinary((u_char *)tok_val,slave_nio->lacp.actorSystemID, 6) != 6) {
		  myLog(LOG_ERR, "updateBondCounters: permanent HW addr read error: %s", tok_val);
		}
	      }
	    }
	    
	    if(my_strequal(tok_var, "Aggregator ID")) {
	      uint32_t slave_aggID = strtol(tok_val, NULL, 0);
	      if(slave_aggID == aggID) {
		// remember that is the slave port that has the same aggregator ID as the bond
		aggregator_slave_nio = slave_nio;
	      }
	    }
	  }
	}
      }
      
      if(aggregator_slave_nio && !gotActorID) {
	// go back and fill in the actorSystemID on all the slave ports
	shareActorIDFromSlave(sp, bond_nio, aggregator_slave_nio);
      }
      
      fclose(procFile);
    }
  }
  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);
    }
  }
Exemple #18
0
  void agentCB_getCounters_interface(void *magic, SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
  {
    assert(poller->magic);
    HSP *sp = (HSP *)poller->magic;
    
    // device name was copied as userData
    char *devName = (char *)poller->userData;
    
    if(devName) {
      // look up the adaptor objects
      SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, devName);
      if(adaptor && adaptor->userData) {
	HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)adaptor->userData;
      
	// make sure the counters are up to the second
	updateNioCounters(sp);
	
	// see if we were able to discern multicast and broadcast counters
	// by polling for ethtool stats.  Be careful to use unsigned 32-bit
	// arithmetic here:
#define UNSUPPORTED_SFLOW_COUNTER32 (uint32_t)-1
	uint32_t pkts_in = adaptorNIO->nio.pkts_in;
	uint32_t pkts_out = adaptorNIO->nio.pkts_out;
	uint32_t mcasts_in =  UNSUPPORTED_SFLOW_COUNTER32;
	uint32_t mcasts_out =  UNSUPPORTED_SFLOW_COUNTER32;
	uint32_t bcasts_in =  UNSUPPORTED_SFLOW_COUNTER32;
	uint32_t bcasts_out =  UNSUPPORTED_SFLOW_COUNTER32;
#ifdef HSP_ETHTOOL_STATS
	// only do this if we were able to find all four
	// via ethtool, otherwise it would just be too weird...
	if(adaptorNIO->et_nfound == 4) {
	  mcasts_in = (uint32_t)adaptorNIO->et_total.mcasts_in;
	  bcasts_in = (uint32_t)adaptorNIO->et_total.bcasts_in;
	  pkts_in -= (mcasts_in + bcasts_in);
	  mcasts_out = (uint32_t)adaptorNIO->et_total.mcasts_out;
	  bcasts_out = (uint32_t)adaptorNIO->et_total.bcasts_out;
	  pkts_out -= (mcasts_out + bcasts_out);
	}
#endif
	// generic interface counters
	SFLCounters_sample_element elem = { 0 };
	elem.tag = SFLCOUNTERS_GENERIC;
	elem.counterBlock.generic.ifIndex = poller->dsi.ds_index;
	elem.counterBlock.generic.ifType = 6; // assume ethernet
	elem.counterBlock.generic.ifSpeed = adaptor->ifSpeed;
	elem.counterBlock.generic.ifDirection = adaptor->ifDirection;
	elem.counterBlock.generic.ifStatus = adaptorNIO->up ? (SFLSTATUS_ADMIN_UP | SFLSTATUS_OPER_UP) : 0;
	elem.counterBlock.generic.ifPromiscuousMode = adaptor->promiscuous;
	elem.counterBlock.generic.ifInOctets = adaptorNIO->nio.bytes_in;
	elem.counterBlock.generic.ifInUcastPkts = pkts_in;
	elem.counterBlock.generic.ifInMulticastPkts = mcasts_in;
	elem.counterBlock.generic.ifInBroadcastPkts = bcasts_in;
	elem.counterBlock.generic.ifInDiscards = adaptorNIO->nio.drops_in;
	elem.counterBlock.generic.ifInErrors = adaptorNIO->nio.errs_in;
	elem.counterBlock.generic.ifInUnknownProtos = UNSUPPORTED_SFLOW_COUNTER32;
	elem.counterBlock.generic.ifOutOctets = adaptorNIO->nio.bytes_out;
	elem.counterBlock.generic.ifOutUcastPkts = pkts_out;
	elem.counterBlock.generic.ifOutMulticastPkts = mcasts_out;
	elem.counterBlock.generic.ifOutBroadcastPkts = bcasts_out;
	elem.counterBlock.generic.ifOutDiscards = adaptorNIO->nio.drops_out;
	elem.counterBlock.generic.ifOutErrors = adaptorNIO->nio.errs_out;
	SFLADD_ELEMENT(cs, &elem);

	// add optional interface name struct
	SFLCounters_sample_element pn_elem = { 0 };
	pn_elem.tag = SFLCOUNTERS_PORTNAME;
	pn_elem.counterBlock.portName.portName.len = my_strlen(devName);
	pn_elem.counterBlock.portName.portName.str = devName;
	SFLADD_ELEMENT(cs, &pn_elem);

	// possibly include LACP struct for bond master or slave
	SFLCounters_sample_element lacp_elem = { 0 };
	if(adaptorNIO->bond_master
	   || adaptorNIO->bond_slave) {
	  updateBondCounters(sp, adaptor);
	  lacp_elem.tag = SFLCOUNTERS_LACP;
	  lacp_elem.counterBlock.lacp = adaptorNIO->lacp; // struct copy
	  SFLADD_ELEMENT(cs, &lacp_elem);
	}
	sfl_poller_writeCountersSample(poller, cs);
      }
    }
  }
Exemple #19
0
  int readPackets(HSP *sp)
  {
    int batch = 0;
    static uint32_t MySkipCount=1;

    if(sp->sFlow->sFlowSettings == NULL) {
      // config was turned off
      return 0;
    }

    if(sp->sFlow->sFlowSettings->ulogSubSamplingRate == 0) {
      // packet sampling was disabled by setting desired rate to 0
      return 0;
    }

    if(sp->ulog_soc) {
      for( ; batch < HSP_READPACKET_BATCH; batch++) {
	char buf[HSP_MAX_ULOG_MSG_BYTES];
	socklen_t peerlen = sizeof(sp->ulog_peer);
	int len = recvfrom(sp->ulog_soc,
			   buf,
			   HSP_MAX_ULOG_MSG_BYTES,
			   0,
			   (struct sockaddr *)&sp->ulog_peer,
			   &peerlen);
	if(len <= 0) break;
	if(debug > 1) myLog(LOG_INFO, "got ULOG msg: %u bytes", len);
	for(struct nlmsghdr *msg = (struct nlmsghdr *)buf; NLMSG_OK(msg, len); msg=NLMSG_NEXT(msg, len)) {

	  if(debug > 1) {
	    myLog(LOG_INFO, "netlink (%u bytes left) msg [len=%u type=%u flags=0x%x seq=%u pid=%u]",
		  len,
		  msg->nlmsg_len,
		  msg->nlmsg_type,
		  msg->nlmsg_flags,
		  msg->nlmsg_seq,
		  msg->nlmsg_pid);
	  }

          // check for drops indicated by sequence no
          uint32_t droppedSamples = 0;
          if(sp->ulog_seqno) {
            droppedSamples = msg->nlmsg_seq - sp->ulog_seqno - 1;
            if(droppedSamples) {
              sp->ulog_drops += droppedSamples;
            }
          }
          sp->ulog_seqno = msg->nlmsg_seq;

	  switch(msg->nlmsg_type) {
	  case NLMSG_NOOP:
	  case NLMSG_ERROR:
	  case NLMSG_OVERRUN:
	    // ignore these
	    break;
	  case NLMSG_DONE: // last in multi-part
	  default:
	    {

	      if(--MySkipCount == 0) {
		/* reached zero. Set the next skip */
		MySkipCount = sfl_random((2 * sp->sFlow->sFlowSettings->ulogSubSamplingRate) - 1);

		/* and take a sample */

		// we're seeing type==111 on Fedora14
		//if(msg->nlmsg_flags & NLM_F_REQUEST) { }
		//if(msg->nlmsg_flags & NLM_F_MULTI) { }
		//if(msg->nlmsg_flags & NLM_F_ACK) { }
		//if(msg->nlmsg_flags & NLM_F_ECHO) { }
		ulog_packet_msg_t *pkt = NLMSG_DATA(msg);
		
		if(debug > 1) {
		  myLog(LOG_INFO, "mark=%u ts=%s hook=%u in=%s out=%s len=%u prefix=%s maclen=%u",
			pkt->mark,
			ctime(&pkt->timestamp_sec),
			pkt->hook,
			pkt->indev_name,
			pkt->outdev_name,
			pkt->data_len,
			pkt->prefix,
			pkt->mac_len);
		  if(pkt->mac_len == 14) {
		    u_char macdst[12], macsrc[12];
		    printHex(pkt->mac+6,6,macsrc,12,NO);
		    printHex(pkt->mac+0,6,macdst,12,NO);
		    uint16_t ethtype = (pkt->mac[12] << 8) + pkt->mac[13];
		    myLog(LOG_INFO, "%s -> %s (ethertype=0x%04X)", macsrc, macdst, ethtype);
		  }
		}

		
		SFL_FLOW_SAMPLE_TYPE fs = { 0 };
	
		SFLAdaptor *sampler_dev = NULL;
                int inIsLoopback=0, outIsLoopback=0;
 
		// set the ingress and egress ifIndex numbers.
		// Can be "INTERNAL" (0x3FFFFFFF) or "UNKNOWN" (0).
		if(pkt->indev_name[0]) {
		  SFLAdaptor *in = adaptorListGet(sp->adaptorList, pkt->indev_name);
		  if(in) {
		    fs.input = in->ifIndex;
                    // record whether this was a loopback or not - used below
                    HSPAdaptorNIO *inNIO = (HSPAdaptorNIO *)in->userData;
                    inIsLoopback = inNIO->loopback;
#ifdef HSF_CUMULUS
                    // On Cumulus Linux the sampling direction is indicated in the low
                    // bit of the pkt->hook field: 0==ingress,1==egress
                    if((pkt->hook & 1) == 0) {
                      sampler_dev = in;
                    }
#else
                    // set this provisionally - may be overidden below
	            sampler_dev = in;
#endif
		  }
		}
		else {
		  fs.input = SFL_INTERNAL_INTERFACE;
		}
		if(pkt->outdev_name[0]) {
		  SFLAdaptor *out = adaptorListGet(sp->adaptorList, pkt->outdev_name);
		  if(out && out->ifIndex) {
		    fs.output = out->ifIndex;
                    HSPAdaptorNIO *outNIO = (HSPAdaptorNIO *)out->userData;
                    outIsLoopback = outNIO->loopback;
#ifdef HSF_CUMULUS
                    // On Cumulus Linux the sampling direction is indicated in the low
                    // bit of the pkt->hook field: 0==ingress,1==egress
                    if((pkt->hook & 1) == 1) {
                      sampler_dev = out;
                    }
#else
                    // If one of them is not a loopback interface, then assume the
                    // sample was taken there.  In a typical scenario most samples
	            // will be "lo" -> "eth0" or "eth0" -> "lo", so this ensures that
                    // that we make that look like bidirectional sampling on eth0.
                    if(sampler_dev == NULL
                       || (inIsLoopback && !outIsLoopback)) {
		      sampler_dev = out;
                    }
#endif
		  }
		}
		else {
		  fs.output = SFL_INTERNAL_INTERFACE;
		}

		// must have a sampler_dev with an ifIndex
		if(sampler_dev && sampler_dev->ifIndex) {
                  HSPAdaptorNIO *samplerNIO = (HSPAdaptorNIO *)sampler_dev->userData;

                  if(debug > 2) {
                    myLog(LOG_INFO, "selected sampler %s (loopback in=%d out=%d)",
                          sampler_dev->deviceName, 
                          inIsLoopback,
                          outIsLoopback);
                  }

		  SFLSampler *sampler = getSampler(sp, sampler_dev);
		  
		  if(sampler) {
		    SFLFlow_sample_element hdrElem = { 0 };
		    hdrElem.tag = SFLFLOW_HEADER;
		    uint32_t FCS_bytes = 4;
		    uint32_t maxHdrLen = sampler->sFlowFsMaximumHeaderSize;
		    hdrElem.flowType.header.frame_length = pkt->data_len + FCS_bytes;
		    hdrElem.flowType.header.stripped = FCS_bytes;
		    
		    u_char hdr[HSP_MAX_HEADER_BYTES];
		    
		    if(pkt->mac_len == 14) {
		      // set the header_protocol to ethernet and
		      // reunite the mac header and payload in one buffer
		      hdrElem.flowType.header.header_protocol = SFLHEADER_ETHERNET_ISO8023;
		      memcpy(hdr, pkt->mac, 14);
		      maxHdrLen -= 14;
		      uint32_t payloadBytes = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
		      memcpy(hdr+14, pkt->payload, payloadBytes);
		      hdrElem.flowType.header.header_length = payloadBytes + 14;
		      hdrElem.flowType.header.header_bytes = hdr;
		      hdrElem.flowType.header.frame_length += 14;
		    }
		    else {
		      // no need to copy - just point at the payload
		      u_char ipversion = pkt->payload[0] >> 4;
		      if(ipversion != 4 && ipversion != 6) {
			if(debug) myLog(LOG_ERR, "received non-IP packet. Encapsulation is unknown");
		      }
		      else {
			hdrElem.flowType.header.header_protocol = (ipversion == 4) ? SFLHEADER_IPv4 : SFLHEADER_IPv6;
			hdrElem.flowType.header.stripped += 14; // assume ethernet was (or will be) the framing
			hdrElem.flowType.header.header_length = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
			hdrElem.flowType.header.header_bytes = pkt->payload;
		      }
		    }
		    
		    SFLADD_ELEMENT(&fs, &hdrElem);
		    // 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.
		    // If it's a switch port then samplerNIO->sampling_n will be set, so that
		    // takes precendence (allows different ports to have different sampling
		    // settings).
		    uint32_t actualSamplingRate = samplerNIO->sampling_n ?: sp->sFlow->sFlowSettings->ulogActualSamplingRate;
		    fs.sampling_rate = actualSamplingRate;
		    
		    // estimate the sample pool from the samples.  Could maybe do this
		    // above with the (possibly more granular) ulogSamplingRate, but then
		    // we would have to look up the sampler object every time, which
		    // might be too expensive in the case where ulogSamplingRate==1.
		    sampler->samplePool += actualSamplingRate;
		    
                    // accumulate any dropped-samples we detected against whichever sampler
                    // sends the next sample. This is not perfect,  but is likely to accrue
                    // drops against the point whose sampling-rate needs to be adjusted.
                    samplerNIO->ulog_drops += droppedSamples;
                    fs.drops = samplerNIO->ulog_drops;
		    sfl_sampler_writeFlowSample(sampler, &fs);
		  }
		}
	      }
	    }
	  } 
	}
      }
  int selectAgentAddress(HSP *sp, int *p_changed) {

    int selected = NO;
    SFLAddress previous = sp->sFlow->agentIP;

    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");
      selected = YES;
    }
    else if(sp->sFlow->explicitAgentDevice && sp->sFlow->agentDevice) {
      // it may have been defined as agent=<device>
      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");
	selected = YES;
      }
    }
    else {
      // 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;
	  // take the highest priority one,  but if we have more than one with the same
	  // priority then choose the one with the lowest (non-zero) ifIndex number:
	  if(adaptorNIO->ipPriority > ipPriority
	     || (adaptorNIO->ipPriority == ipPriority
		 && adaptor->ifIndex
		 && selectedAdaptor
		 && (selectedAdaptor->ifIndex == 0
		     || adaptor->ifIndex < selectedAdaptor->ifIndex))) {
	    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");
	selected = YES;
      }
    }

    if(p_changed) {
      if(SFLAddress_equal(&previous, &sp->sFlow->agentIP)) {
	*p_changed = YES;
      }
      else {
	*p_changed = NO;
      }
    }
    
    return selected;
  }
Exemple #21
0
/**
 * Call back function called when it is time to sample the Hyper-V switch interface counters.
 * Uses the poller->userData to find the device name (ie switch port guid) which identifies
 * the counter instance for the switch port.
 */
void getCounters_interface(void *magic, SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
 {
	 HSP *sp = (HSP *)poller->magic;
    
    // device name was copied as userData
    char *deviceName = (char *)poller->userData;
	myLog(LOG_INFO, "getCounters_interface: dsClass=%u, dsIndex=%u, deviceName=%s", 
		  poller->dsi.ds_class, poller->dsi.ds_index, deviceName);

	if (deviceName) {
		//find the vadaptor for the deviceName
		SFLAdaptor *vAdaptor = adaptorListGet(sp->vAdaptorList, deviceName);
		if (vAdaptor != NULL) {
			myLog(LOG_INFO, "getCounters_interface: found adaptor index=%u", vAdaptor->ifIndex);
			wchar_t *instance = ((HVSVPortInfo *)vAdaptor->userData)->portCountersInstance;
			if (!instance) {
				myLog(LOG_INFO, "getCounters_interface: counters instance name not set for %s", deviceName);
				return;
			}
			//Get the counter data
			SFLCounters_sample_element elem = { 0 };
			elem.tag = SFLCOUNTERS_GENERIC;
			elem.counterBlock.generic.ifIndex = poller->dsi.ds_index;
			elem.counterBlock.generic.ifType = 6; // assume ethernet
			elem.counterBlock.generic.ifSpeed = vAdaptor->ifSpeed;
			elem.counterBlock.generic.ifDirection = vAdaptor->ifDirection;
			elem.counterBlock.generic.ifStatus = 3; // ifAdminStatus==up, ifOperstatus==up
			elem.counterBlock.generic.ifPromiscuousMode = vAdaptor->promiscuous;
			PDH_HQUERY query;
			if (PdhOpenQuery(NULL, 0, &query) == ERROR_SUCCESS) {
				PDH_HCOUNTER bytesIn, pktsIn, mcastsIn, bcastsIn, discardsIn;
				PDH_HCOUNTER bytesOut, pktsOut, mcastsOut, bcastsOut, discardsOut;
				if (addCounter(instance, IF_COUNTER_BYTES_IN, &query, &bytesIn) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_PACKETS_IN, &query, &pktsIn) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_MULTICASTS_IN, &query, &mcastsIn) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_BROADCASTS_IN, &query, &bcastsIn) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_DISCARDS_IN, &query, &discardsIn) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_BYTES_OUT, &query, &bytesOut) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_PACKETS_OUT, &query, &pktsOut) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_MULTICASTS_OUT, &query, &mcastsOut) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_BROADCASTS_OUT, &query, &bcastsOut) == ERROR_SUCCESS &&
					addCounter(instance, IF_COUNTER_DISCARDS_OUT, &query, &discardsOut) == ERROR_SUCCESS &&
					PdhCollectQueryData(query) == ERROR_SUCCESS) {
					elem.counterBlock.generic.ifInOctets = getRawCounterValue(&bytesIn);
					elem.counterBlock.generic.ifInUcastPkts = (uint32_t)getRawCounterValue(&pktsIn);
					elem.counterBlock.generic.ifInMulticastPkts = (uint32_t)getRawCounterValue(&mcastsIn);
					elem.counterBlock.generic.ifInBroadcastPkts = (uint32_t)getRawCounterValue(&bcastsIn);
					elem.counterBlock.generic.ifInDiscards = (uint32_t)getRawCounterValue(&discardsIn);
					elem.counterBlock.generic.ifOutOctets = getRawCounterValue(&bytesOut);
					elem.counterBlock.generic.ifOutUcastPkts = (uint32_t)getRawCounterValue(&pktsOut);
					elem.counterBlock.generic.ifOutMulticastPkts = (uint32_t)getRawCounterValue(&mcastsOut);
					elem.counterBlock.generic.ifOutBroadcastPkts = (uint32_t)getRawCounterValue(&bcastsOut);
					elem.counterBlock.generic.ifOutDiscards = (uint32_t) getRawCounterValue(&discardsOut);
				}
				PdhCloseQuery(query);
			}
			elem.counterBlock.generic.ifInErrors = UNKNOWN_COUNTER;
			elem.counterBlock.generic.ifOutErrors = UNKNOWN_COUNTER;
			elem.counterBlock.generic.ifInUnknownProtos = UNKNOWN_COUNTER;
			SFLADD_ELEMENT(cs, &elem);
			myLog(LOG_INFO, "getCounters_interface:\n\tifIndex:\t%u\n\tifType:\t%u\n\tifSpeed:\t%I64u\n"
				"\tifDirection:\t%u\n\tifStatus:\t%u\n\tpromiscuous:\t%u\n\tinOctets:\t%I64u\n\tinUcast:\t%u\n"
				"\tinMulticast:\t%u\n\tinBroadcast:\t%u\n\tinDiscards:\t%u\n\tinErrors:\t%u\n\toutOctets:\t%I64u\n"
				"\toutUcast:\t%u\n\toutMulticast:\t%u\n\toutBroadcast:\t%u\n\toutDiscards:\t%u\n\toutErrors:\t%u",
				elem.counterBlock.generic.ifIndex, elem.counterBlock.generic.ifType, elem.counterBlock.generic.ifSpeed, 
				elem.counterBlock.generic.ifDirection, elem.counterBlock.generic.ifStatus, 
				elem.counterBlock.generic.ifPromiscuousMode, elem.counterBlock.generic.ifInOctets, 
				elem.counterBlock.generic.ifInUcastPkts, elem.counterBlock.generic.ifInMulticastPkts, 
				elem.counterBlock.generic.ifInBroadcastPkts, elem.counterBlock.generic.ifInDiscards, 
				elem.counterBlock.generic.ifInErrors, elem.counterBlock.generic.ifOutOctets, 
				elem.counterBlock.generic.ifOutUcastPkts, elem.counterBlock.generic.ifOutMulticastPkts, 
				elem.counterBlock.generic.ifOutBroadcastPkts, elem.counterBlock.generic.ifOutDiscards, 
				elem.counterBlock.generic.ifOutErrors);
			sfl_poller_writeCountersSample(poller, cs);
		}
	}
}