/** * Enumerates the adapters for this host by first trying to enumerate * MSFT_NetAdapter and if this fails (root\standardcimv2 namespace does * not exist prior to Win8/2012) then tries to enumerate Win32_NetworkAdapter * where NetConnectionStatus=2 (to exclude tunnels, ras, wan miniports etc). * Uses the information to populate the sp->adaptorList structure. * Optionally gets the IP address (v4 and/or v6) from the approriate associated * objects (MSFT_NetIpAddress or Win32_NetworkAdapterConfiguration). * This is only required when trying to identify the IP addresses that could be * used as the agent address. * MSFT_NetAdapter is preferred, since the interface description is used for * the interface counter instance name, and this description does not * change when teaming is enabled, whereas Win32_NetworkAdapter.Name does * change when teaming is enabled. */ void readInterfaces(HSP *sp, BOOL getIPAddr) { if (sp->adaptorList == NULL) { sp->adaptorList = adaptorListNew(); } adaptorListMarkAll(sp->adaptorList); if (!readInterfacesMsft(sp->adaptorList, getIPAddr)) { readInterfacesWin32(sp->adaptorList, getIPAddr); } adaptorListFreeMarked(sp->adaptorList, freeAdaptorInfo); }
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; }
/** * 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; }
/** * 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. */ void readInterfaces(HSP *sp, BOOL getIpAddr) { if (sp->adaptorList == NULL) { sp->adaptorList = adaptorListNew(); } adaptorListMarkAll(sp->adaptorList); 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,"readInterfaces: connectToWMI failed for namespace %S", path); return; } 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,"readInterfaces: ExecQuery() failed for query %S error=0x%x", query, hr); SysFreeString(query); pNamespace->Release(); CoUninitialize(); return; } 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(sp->adaptorList, (char *)deviceName, mac, sizeof(HSPAdaptorNIO)); // clear the mark so we don't free it below 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; readIpAddresses(pNamespace, adapterObj, adaptor); } myLog(LOG_INFO,"ReadInterfaces:\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(); CoUninitialize(); adaptorListFreeMarked(sp->adaptorList, freeAdaptorInfo); }