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;
  }
int readInterfaces(HSP *sp)
{
  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];
    while(fgets(line, MAX_PROC_LINE_CHARS, procFile)) {
      if(debug) myLog(LOG_INFO, "/proc/net/dev line: %s", line);
      // the device name is always the token before the ":"
      char *devName = strtok(line, ":");
      if(devName) {
	devName = trimWhitespace(devName);
	if(devName && strlen(devName) < IFNAMSIZ) {
	  // we set the ifr_name field to make our queries
	  strcpy(ifr.ifr_name, devName);

	  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 hasBroadcast = (ifr.ifr_flags & IFF_BROADCAST);
	    //int pointToPoint = (ifr.ifr_flags & IFF_POINTOPOINT);

	    // used to igore loopback interfaces here, but now those
	    // are filtered at the point where we roll together the
	    // counters.
	    if(up) {
	      
	       // 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 = 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;
	      adaptorNIO->loopback = loopback;
	      adaptorNIO->bond_master = bond_master;
	      adaptorNIO->vlan = HSP_VLAN_ALL; // may be modified below

	      // 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;
		//}
	      }
	      
	      // Try to get the ethtool info for this interface so we can infer the
	      // ifDirection and ifSpeed. Learned from openvswitch (http://www.openvswitch.org).
	      struct ethtool_cmd ecmd = { 0 };
	      ecmd.cmd = ETHTOOL_GSET;
	      ifr.ifr_data = (char *)&ecmd;
	      if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
		adaptor->ifDirection = ecmd.duplex ? 1 : 2;
		uint64_t ifSpeed_mb = ecmd.speed;
		// ethtool_cmd_speed(&ecmd) is available in newer systems and uses the
		// speed_hi field too,  but we would need to run autoconf-style
		// tests to see if it was there and we are trying to avoid that.
		if(ifSpeed_mb == (uint16_t)-1 ||
		   ifSpeed_mb == (uint32_t)-1) {
		  // unknown
		  adaptor->ifSpeed = 0;
		}
		else {
		  adaptor->ifSpeed = ifSpeed_mb * 1000000;
		}
	      }
	    }
	  }
	}
      }
    }
    fclose(procFile);
  }
  
  close (fd);

  // now remove and free any that are still marked
  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);

  return sp->adaptorList->num_adaptors;
}
  int readInterfaces_getifaddrs(HSP *sp)
  {
    struct ifaddrs *ifap = NULL;
    int interfaces_found = 0;
    
    if(getifaddrs(&ifap) != 0) {
      myLog(LOG_ERR, "getifaddrs() failed : %s", strerror(errno));
      return 0;
    }
    for(struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) {
      int up = (ifa->ifa_flags & IFF_UP) ? 1 : 0;
      int loopback = (ifa->ifa_flags & IFF_LOOPBACK) ? 1: 0;
      int promisc = (ifa->ifa_flags & IFF_PROMISC) ? 1 : 0;
      int bond_master = 0; // (ifa->ifa_flags & IFF_MASTER) ? 1 : 0;
	
      if(debug) myLog(LOG_INFO, "ifa_name=%s up=%d loopback=%d", ifa->ifa_name, up, loopback);
	
      if(up == 0) continue;
      interfaces_found++;

      // try to get the MAC
      u_char *macptr = NULL;
      u_char macAddr[6];
      if(readMacAddress(ifa->ifa_name, macAddr, 6)) {
	macptr = macAddr;
      }

      // find or create the "adaptor" entry for this dev
      SFLAdaptor *adaptor = adaptorListAdd(sp->adaptorList, ifa->ifa_name, macptr, sizeof(HSPAdaptorNIO));
			
      // this flag might belong in the adaptorNIO struct
      adaptor->promiscuous = promisc;
			
      // remember some useful flags in the userData structure
      HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)adaptor->userData;
      adaptorNIO->loopback = loopback;
      adaptorNIO->bond_master = bond_master;
      adaptorNIO->vlan = HSP_VLAN_ALL; // may be modified below

      // we don't expect to read counters from this device - it's
      // really just there to learn the IP address/MAC addresses
      adaptorNIO->forCounters = NO;

      SFLAddress addr = { 0 };

      if (AF_INET == ifa->ifa_addr->sa_family) {
	struct sockaddr_in *s = (struct sockaddr_in *)ifa->ifa_addr;
	addr.type = SFLADDRESSTYPE_IP_V4;
	addr.address.ip_v4.addr = s->sin_addr.s_addr;
      }
      else if(AF_INET6 == ifa->ifa_addr->sa_family) {
	struct sockaddr_in6 *s = (struct sockaddr_in6 *)ifa->ifa_addr;
	addr.type = SFLADDRESSTYPE_IP_V6;
	memcpy(&addr.address.ip_v6.addr, &s->sin6_addr, 16);
      }
      EnumIPSelectionPriority ipPriority = agentAddressPriority(sp,
								&addr,
								adaptorNIO->vlan,
								adaptorNIO->loopback);
      if(adaptor->marked ||
	 ipPriority > adaptorNIO->ipPriority) {
	adaptorNIO->ipAddr = addr;
	adaptorNIO->ipPriority = ipPriority;

	if(debug) {
	  char buf[51];
	  myLog(LOG_INFO, "interface: %s family: %d IP: %s priority: %d",
		ifa->ifa_name,
		ifa->ifa_addr->sa_family,
		inet_ntop(ifa->ifa_addr->sa_family, &adaptorNIO->ipAddr.address, buf, 50),
		ipPriority);
	}
      }
	
      // clear the mark so we don't free it below
      adaptor->marked = NO; 
    }

    // clean up
    freeifaddrs(ifap);

    if(debug) myLog(LOG_INFO, "found (and unmarked) %d interfaces via getifaddrs", interfaces_found);

    return interfaces_found;
  }
  int readInterfaces_kstat(HSP *sp)
  {
    int noErr = 1;
    kstat_ctl_t *kc = NULL;
    kstat_t *ksp;
#ifndef KSNAME_BUFFER_SIZE
#define KSNAME_BUFFER_SIZE 32
#endif
    char devName[KSNAME_BUFFER_SIZE];
    int interfaces_found = 0;

    int fd = socket (PF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
      myLog(LOG_ERR, "error opening socket: %d (%s)\n", errno, strerror(errno));
      noErr = 0;
    }
    struct lifreq lifr;
    memset(&lifr, 0, sizeof(lifr));
	
    if (noErr) {
      kc = kstat_open();
      if (NULL == kc) {
	noErr = 0;
	myLog(LOG_ERR, "readInterfaces kstat_open failed");
      }
    }

    if (noErr) {
      for (ksp = kc->kc_chain; NULL != ksp; ksp = ksp->ks_next) {
	// Look for kstats of class "net"
	if (ksp->ks_class
	    && ksp->ks_module
	    && ksp->ks_name
	    && !strncmp(ksp->ks_class, "net", 3)) {

	  if(debug > 2) {
	    myLog(LOG_INFO, "ksp class=%s, module=%s name=%s",
		  ksp->ks_class ?: "NULL",
		  ksp->ks_module ?: "NULL",
		  ksp->ks_name ?: "NULL");
	  }

#ifndef KSNAME_BUFFER_SIZE
#define KSNAME_BUFFER_SIZE 32
#endif
	  int includeDev = NO;

          // Concatenate the module name and instance number to create device name
	  snprintf(devName, KSNAME_BUFFER_SIZE, "%s%d", ksp->ks_module, ksp->ks_instance);


#if (HSP_SOLARIS >= 5011)
          // on solaris 11 we collect name=phys, module!=aggr,vnic for counter purposes.
          // and don't use any of the others for counters.
          if(my_strequal(ksp->ks_name, "phys")
             && !my_strequal(ksp->ks_module, "aggr") 
             && !my_strequal(ksp->ks_module, "vnic")) {
	    includeDev = YES;
          }
#else
	  // If device name equals the kstat's name, then we have a kstat the describes the device. 
	  if (!strncmp(ksp->ks_name, devName, KSNAME_BUFFER_SIZE)) {
            includeDev = YES;
          }
#endif
          if(includeDev == NO) continue;

	  // since we now rely on getifaddrs or lifrec to learn about IP/MAC details,
	  // we are only interested in collecting interfaces to get counters-from here.

	  // find or create the "adaptor" entry for this dev
	  SFLAdaptor *adaptor = adaptorListAdd(sp->adaptorList, devName, NULL, sizeof(HSPAdaptorNIO));
		
	  // clear the mark so we don't free it below
	  adaptor->marked = NO; 
	  interfaces_found++;
			    
	  // remember some useful flags in the userData structure
	  HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)adaptor->userData;
	  adaptorNIO->forCounters = YES;
	  adaptorNIO->vlan = HSP_VLAN_ALL; // may be modified below
		
#if 0
	  kstat_t *ksp_tmp;
	  kstat_named_t *knp;
	  ksp_tmp = kstat_lookup(kc, ksp->ks_module, ksp->ks_instance, "mac");
	  if (NULL == ksp_tmp) {
	    myLog(LOG_ERR, "kstat_lookup error (module: %s, inst: %d, name: mac): %s",
		  ksp->ks_module, ksp->ks_instance, strerror(errno));
	  }
	  else {
	    if (-1 == kstat_read(kc, ksp_tmp, NULL)) {
	      myLog(LOG_ERR, "kstat_read error (module: %s, name: %s, class: %s): %s",
		    ksp->ks_module, ksp->ks_name, ksp->ks_class, strerror(errno));
	    }
	    else {
	      knp = kstat_data_lookup(ksp_tmp, "ifspeed");
	      if(knp) {
		adaptor->ifSpeed = knp->value.ui64;
	      }
	      knp = kstat_data_lookup(ksp_tmp, "link_up");
	      if(knp) {
		myLog(LOG_INFO, "kstat link_up = %d", knp->value.ui32);
	      }
	      
	      uint32_t direction = 0;
	      knp = kstat_data_lookup(ksp_tmp, "link_duplex");
	      if(knp) {
		// The full-duplex and half-duplex values are reversed between the
		// comment in sflow.h and link_duplex man page.
		if (knp->value.ui32 == 1)
		  direction = 2;
		else if (knp->value.ui32 == 2)
		  direction = 1;
		adaptor->ifDirection = direction;
	      }
	    }
	  }
#endif
	}
      }
    }
  int readInterfaces_lifreq(HSP *sp)
  {
    int interfaces_found = 0;
    struct lifnum ln;
    struct lifconf lc;
    struct lifreq rq;
    int i, nFd;
    int up, loopback, promisc, bond_master;
    nFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (nFd >= 0)
      {
        ln.lifn_family = AF_INET;
        ln.lifn_flags = 0;
        if (ioctl(nFd, SIOCGLIFNUM, &ln) == 0) {
	  lc.lifc_family = AF_INET;
	  lc.lifc_flags = 0;
	  lc.lifc_len = sizeof(struct lifreq) * ln.lifn_count;
	  lc.lifc_buf = (caddr_t)my_calloc(lc.lifc_len);
	  if (ioctl(nFd, SIOCGLIFCONF, &lc) == 0) {
	    if(debug > 2) myLog(LOG_INFO, "ln.lifn_count = %u", ln.lifn_count);
	    for (i = 0; i < ln.lifn_count; i++) {
	      strcpy(rq.lifr_name, lc.lifc_req[i].lifr_name);
	      myLog(LOG_INFO, "interface: %s", rq.lifr_name);
	      if (ioctl(nFd, SIOCGLIFFLAGS, &rq) == 0) {
		if(debug) myLog(LOG_INFO, "interface:%s flags=%x",
				rq.lifr_name,
				rq.lifr_index);
		up = (rq.lifr_flags & IFF_UP) ? 1 : 0;
		loopback = (rq.lifr_flags & IFF_LOOPBACK) ? 1: 0;
		promisc = (rq.lifr_flags & IFF_PROMISC) ? 1 : 0;
		// TODO: No IFF_MASTER so set to 0
		bond_master = 0;
		if(up == 0) continue;
		interfaces_found++;
	      
		// get MAC if we can
		u_char *macptr = NULL;
		u_char macAddr[6];
		if(readMacAddress(rq.lifr_name, macAddr, 6)) {
		  macptr = macAddr;
		}

		// find or create the "adaptor" entry for this dev
		SFLAdaptor *adaptor = adaptorListAdd(sp->adaptorList, rq.lifr_name, macptr, 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;
		adaptorNIO->loopback = loopback;
		adaptorNIO->bond_master = bond_master;
		adaptorNIO->vlan = HSP_VLAN_ALL; // may be modified below
		adaptorNIO->forCounters = NO;

		if (ioctl(nFd, SIOCGLIFINDEX, &rq) == 0) {
		  if(debug) myLog(LOG_INFO, "interface: %s ifIndex=%d",
				  rq.lifr_name,
				  rq.lifr_index);
		  adaptor->ifIndex = rq.lifr_index;
		}

		if (ioctl(nFd, SIOCGLIFADDR, &rq) == 0) {
		  char buf[51];
			  
		  if (AF_INET == rq.lifr_addr.ss_family) {
		    struct sockaddr_in *s = (struct sockaddr_in *)&rq.lifr_addr;
		    adaptorNIO->ipAddr.type = SFLADDRESSTYPE_IP_V4;
		    adaptorNIO->ipAddr.address.ip_v4.addr = s->sin_addr.s_addr;
		  }
		  else if(AF_INET6 == rq.lifr_addr.ss_family) {
		    /* I think we have to do the whole thing with an IPv6 raw socket
		       before we can get an IPv6 address this way,  so this will
		       probably not work.  Better to use getifaddrs() if we can. */
		    struct sockaddr_in6 *s = (struct sockaddr_in6 *)&rq.lifr_addr;
		    adaptorNIO->ipAddr.type = SFLADDRESSTYPE_IP_V6;
		    memcpy(&adaptorNIO->ipAddr.address.ip_v6.addr, &s->sin6_addr, 16);
		  }
		  if(debug) {
		    myLog(LOG_INFO, "lifreq interface: %s family: %d IP: %s",
			  rq.lifr_name,
			  rq.lifr_addr.ss_family,
			  inet_ntop(rq.lifr_addr.ss_family, &adaptorNIO->ipAddr.address, buf, 51));
		  }
		}
	      }
	    }
	  }
	  
	  my_free(lc.lifc_buf);
	}
        close(nFd);
      }
    
    if(debug) myLog(LOG_INFO, "found (and unmarked) %d interfaces via lifrec", interfaces_found);
    return interfaces_found;
  }
/**
 * Enumerates the adapters for this host from WMI Win32_NetworkAdapter
 * where NetConnectionStatus=2 (to exclude tunnels, ras, wan miniports etc).
 * Uses the information to populate the sp->adaptorList structure.
 * adapter->deviceName = Win32_NetworkAdapter.GUID (converted to 
 * lowercase char with enclosing {} removed)
 * adapter->ifIndex = Win32_NetworkAdapter.InterfaceIndex
 * this is the interface index used in the route table (rather than Index
 * which is the index for the interface in the registry).
 * adapter->userData->countersInstance = Win32_NetworkAdapter.Name 
 * (with reserved chars replaced) 
 * adapter->userData->isVirtual = (Win32_NetworkAdapter.ServiceName == "VMSMP")
 * Optionally gets the IP address (v4 and/or v6) from the associated
 * Win32_NetworkAdapterConfiguration. This is only required when trying
 * to identify the IP addresses that could be used as the agent address.
 * Returns true on success, false on failure.
 */
static BOOL readInterfacesWin32(SFLAdaptorList *adaptorList, BOOL getIpAddr)
{
	BSTR path = SysAllocString(WMI_CIMV2_NS);
	HRESULT hr = S_FALSE;
	IWbemServices *pNamespace = NULL;
	
	hr = connectToWMI(path, &pNamespace);
	SysFreeString(path);
	if (WBEM_S_NO_ERROR != hr) {
		myLog(LOG_ERR,"readInterfacesWin32: connectToWMI failed for namespace %S", path);
		return FALSE;
	}
	BSTR queryLang = SysAllocString(L"WQL");
	BSTR query = SysAllocString(L"SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionStatus=2");
	IEnumWbemClassObject *adapterEnum = NULL;
	hr = pNamespace->ExecQuery(queryLang, query, WBEM_FLAG_FORWARD_ONLY, NULL, &adapterEnum);
	SysFreeString(queryLang);
	if (!SUCCEEDED(hr)) {
		myLog(LOG_ERR,"readInterfacesWin32: ExecQuery() failed for query %S error=0x%x", query, hr);
		SysFreeString(query);
		pNamespace->Release();
		return FALSE;
	}
	SysFreeString(query);
	IWbemClassObject *adapterObj = NULL;
	VARIANT ifIndexVal;
	hr = WBEM_S_NO_ERROR;
	while (WBEM_S_NO_ERROR == hr) {
		ULONG adapterCount = 1;
		hr = adapterEnum->Next(WBEM_INFINITE, 1, &adapterObj, &adapterCount);
		if (0 == adapterCount) {
			break;
		}
		wchar_t *guidString = stringFromWMIProperty(adapterObj, PROP_GUID);
		wchar_t *macString = stringFromWMIProperty(adapterObj, PROP_MAC);
		if (guidString != NULL && macString != NULL) {
			u_char deviceName[FORMATTED_GUID_LEN+1];
			guidToString(guidString, deviceName, FORMATTED_GUID_LEN);
			u_char mac[13];
			wchexToBinary(macString, mac, 13);
			SFLAdaptor *adaptor = adaptorListAdd(adaptorList, 
												(char *)deviceName, mac, 
												sizeof(HSPAdaptorNIO));
			// clear the mark so we don't free it later
			adaptor->marked = FALSE;
			if (WBEM_S_NO_ERROR == adapterObj->Get(PROP_IFINDEX, 0, &ifIndexVal, 0, 0) &&
				(V_VT(&ifIndexVal) == VT_I4 || V_VT(&ifIndexVal) == VT_UI4)) {
				adaptor->ifIndex = ifIndexVal.ulVal;
			}
			HSPAdaptorNIO *userData = (HSPAdaptorNIO *)adaptor->userData;
			if (userData->countersInstance != NULL) {
				my_free(userData->countersInstance);
			}
			wchar_t *counterName = stringFromWMIProperty(adapterObj, PROP_NAME);
			if (counterName != NULL) {
				cleanCounterName(counterName, UTNETWORK_INTERFACE);
				userData->countersInstance = counterName;
			}
			wchar_t *svcName = stringFromWMIProperty(adapterObj, PROP_SVC_NAME);
			if (svcName != NULL) {
				userData->isVirtual = (_wcsicmp(VMSMP, svcName) == 0);
				my_free(svcName);
			}
			if (getIpAddr) {
				userData->ipPriority = IPSP_NONE;
				readIpAddressesWin32(pNamespace, adapterObj, adaptor);
			}
			myLog(LOG_INFO,"ReadInterfacesWin32:\n\tAdapterName:\t%s\n\tifIndex:\t%lu\n\tCounterName:\t%S\n\tisVirtual\t%u",
				adaptor->deviceName, adaptor->ifIndex, userData->countersInstance, userData->isVirtual);
		}
		if (guidString != NULL) {
			my_free(guidString);
		}
		if (macString != NULL) {
			my_free(macString);
		}
		adapterObj->Release();
		VariantClear(&ifIndexVal);
	}
	adapterEnum->Release();
	pNamespace->Release();
	return 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 #8
0
  int readInterfaces(HSP *sp)
  {
    
    char *a;
    u_char dest_mac[6];
    struct sockaddr_in *foo;
    if(sp->adaptorList == NULL) sp->adaptorList = adaptorListNew();
    else adaptorListReset(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.
    
    struct ifaddrs *ifap;
    
    getifaddrs(&ifap);
    for(struct ifaddrs *ifp = ifap; ifp; ifp = ifp->ifa_next) {
      char *devName = ifp->ifa_name;
      if(devName) {
	devName = trimWhitespace(devName);
	// Get the flags for this interface
	int up = (ifp->ifa_flags & IFF_UP) ? YES : NO;
	int loopback = (ifp->ifa_flags & IFF_LOOPBACK) ? YES : NO;
	int promisc =  (ifp->ifa_flags & IFF_PROMISC) ? YES : NO;
	int address_family = ifp->ifa_addr->sa_family;
	if(debug > 1) {
	  myLog(LOG_INFO, "reading interface %s (up=%d, loopback=%d, family=%d)",
		devName,
		up,
		loopback,
		address_family);
	}
	//int hasBroadcast = (ifp->ifa_flags & IFF_BROADCAST);
	//int pointToPoint = (ifp->ifa_flags & IFF_POINTOPOINT);
	
	if(up && !loopback && address_family == AF_INET) {
	  
	  /***** THE NEW WAY ******/
	  
	  find_mac(devName,&dest_mac[0]);
	  SFLAdaptor *adaptor = adaptorListAdd(sp->adaptorList, devName, 
					       (u_char *)&dest_mac); 
	  /*
	    SFLAdaptor *adaptor = adaptorListAdd(sp->adaptorList, devName, 
	    (u_char *)&(ifp->ifa_addr->sa_data)); 
	  */
	  adaptor->promiscuous = promisc;
	  
	  address_family = ifp->ifa_addr->sa_family;
	  
	  if(debug > 1) {
	    myLog(LOG_INFO, "Device: %s",devName);
	    myLog(LOG_INFO, "Address family: %d",address_family);
	  }
	  
	  foo = (struct sockaddr_in *)&ifp->ifa_addr;
	  if (address_family == AF_INET) {
	    
	    a=(char *)&(ifp->ifa_addr->sa_data);
	    a++; a++; // Yep... it really is 2 bytes over 
	    // Only IPV4 below ....
	    memcpy(&adaptor->ipAddr.addr, a, 4);
	    if(debug > 1) {
	      myLog(LOG_INFO, "My IP address = %d.%d.%d.%d", a[0], a[1], a[2], a[3]);
	    }
	  }
	}	  
      }
    }
    updateAdaptorNIO(sp);
    freeifaddrs(ifap);
    return sp->adaptorList->num_adaptors;
    
  }