static int read_ethtool_info(struct ifreq *ifr, int fd, SFLAdaptor *adaptor) { // Try to get the ethtool info for this interface so we can infer the // ifDirection and ifSpeed. Learned from openvswitch (http://www.openvswitch.org). int changed = NO; struct ethtool_cmd ecmd = { 0 }; ecmd.cmd = ETHTOOL_GSET; ifr->ifr_data = (char *)&ecmd; if(ioctl(fd, SIOCETHTOOL, ifr) >= 0) { uint32_t direction = ecmd.duplex ? 1 : 2; if(direction != adaptor->ifDirection) { changed = YES; } adaptor->ifDirection = direction; 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 if(adaptor->ifSpeed != 0) { changed = YES; } adaptor->ifSpeed = 0; } else { uint64_t ifSpeed_bps = ifSpeed_mb * 1000000; if(adaptor->ifSpeed != ifSpeed_bps) { changed = YES; } adaptor->ifSpeed = ifSpeed_bps; } #if (HSP_ETHTOOL_STATS || HSF_DOCKER) // see if the ethtool stats block can give us multicast/broadcast counters too HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)adaptor->userData; adaptorNIO->et_nfound=0; adaptorNIO->et_nctrs = ethtool_num_counters(ifr, fd); if(adaptorNIO->et_nctrs) { struct ethtool_gstrings *ctrNames; uint32_t bytes = sizeof(*ctrNames) + (adaptorNIO->et_nctrs * ETH_GSTRING_LEN); ctrNames = (struct ethtool_gstrings *)my_calloc(bytes); ctrNames->cmd = ETHTOOL_GSTRINGS; ctrNames->string_set = ETH_SS_STATS; ctrNames->len = adaptorNIO->et_nctrs; ifr->ifr_data = (char *)ctrNames; if(ioctl(fd, SIOCETHTOOL, ifr) >= 0) { // copy out one at a time to make sure we have null-termination char cname[ETH_GSTRING_LEN+1]; cname[ETH_GSTRING_LEN] = '\0'; for(int ii=0; ii < adaptorNIO->et_nctrs; ii++) { memcpy(cname, &ctrNames->data[ii * ETH_GSTRING_LEN], ETH_GSTRING_LEN); if(debug) myLog(LOG_INFO, "ethtool counter %s is at index %d", cname, ii); // then see if this is one of the ones we want, // and record the index if it is. #ifdef HSP_ETHTOOL_STATS if(staticStringsIndexOf(HSP_ethtool_mcasts_in_names, cname) != -1) { adaptorNIO->et_idx_mcasts_in = ii+1; adaptorNIO->et_nfound++; } else if(staticStringsIndexOf(HSP_ethtool_mcasts_out_names, cname) != -1) { adaptorNIO->et_idx_mcasts_out = ii+1; adaptorNIO->et_nfound++; } else if(staticStringsIndexOf(HSP_ethtool_bcasts_in_names, cname) != -1) { adaptorNIO->et_idx_bcasts_in = ii+1; adaptorNIO->et_nfound++; } else if(staticStringsIndexOf(HSP_ethtool_bcasts_out_names, cname) != -1) { adaptorNIO->et_idx_bcasts_out = ii+1; adaptorNIO->et_nfound++; } #endif #ifdef HSF_DOCKER if(staticStringsIndexOf(HSP_ethtool_peer_ifindex_names, cname) != -1) { // Now go ahead and make the call to get the peer_ifindex. struct ethtool_stats *et_stats = (struct ethtool_stats *)my_calloc(bytes); et_stats->cmd = ETHTOOL_GSTATS; et_stats->n_stats = adaptorNIO->et_nctrs; ifr->ifr_data = (char *)et_stats; if(ioctl(fd, SIOCETHTOOL, ifr) >= 0) { adaptorNIO->peer_ifIndex = et_stats->data[ii]; if(debug) myLog(LOG_INFO, "Interface %s (ifIndex=%u) has peer_ifindex=%u", adaptor->deviceName, adaptor->ifIndex, adaptorNIO->peer_ifIndex); } } #endif } } my_free(ctrNames); } #endif } return changed; }
/*________________---------------------------__________________ ________________ read_ethtool_info __________________ ----------------___________________________------------------ */ static void read_ethtool_info(struct ifreq *ifr, int fd, SFLAdaptor *adaptor) { // 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; } #ifdef HSP_ETHTOOL_STATS // see if the ethtool stats block can give us multicast/broadcast counters too HSPAdaptorNIO *adaptorNIO = (HSPAdaptorNIO *)adaptor->userData; adaptorNIO->et_nfound=0; struct { struct ethtool_sset_info ssi; uint32_t data; } sset_info; memset(&sset_info, 0, sizeof(sset_info)); sset_info.ssi.cmd = ETHTOOL_GSSET_INFO; sset_info.ssi.sset_mask = (uint64_t)1 << ETH_SS_STATS; ifr->ifr_data = (char *)&sset_info; if(ioctl(fd, SIOCETHTOOL, ifr) >= 0) { if(sset_info.ssi.sset_mask) { adaptorNIO->et_nctrs = sset_info.data; if(adaptorNIO->et_nctrs) { struct ethtool_gstrings *ctrNames; uint32_t bytes = sizeof(ctrNames) + (adaptorNIO->et_nctrs * ETH_GSTRING_LEN); ctrNames = (struct ethtool_gstrings *)my_calloc(bytes); ctrNames->cmd = ETHTOOL_GSTRINGS; ctrNames->string_set = ETH_SS_STATS; ctrNames->len = adaptorNIO->et_nctrs; ifr->ifr_data = (char *)ctrNames; if(ioctl(fd, SIOCETHTOOL, ifr) >= 0) { // copy out one at a time to make sure we have null-termination char cname[ETH_GSTRING_LEN+1]; cname[ETH_GSTRING_LEN] = '\0'; for(int ii=0; ii < adaptorNIO->et_nctrs; ii++) { memcpy(cname, &ctrNames->data[ii * ETH_GSTRING_LEN], ETH_GSTRING_LEN); // then see if this is one of the ones we want, // and record the index if it is. if(staticStringsIndexOf(HSP_ethtool_mcasts_in_names, cname) != -1) { adaptorNIO->et_idx_mcasts_in = ii+1; adaptorNIO->et_nfound++; } else if(staticStringsIndexOf(HSP_ethtool_mcasts_out_names, cname) != -1) { adaptorNIO->et_idx_mcasts_out = ii+1; adaptorNIO->et_nfound++; } else if(staticStringsIndexOf(HSP_ethtool_bcasts_in_names, cname) != -1) { adaptorNIO->et_idx_bcasts_in = ii+1; adaptorNIO->et_nfound++; } else if(staticStringsIndexOf(HSP_ethtool_bcasts_out_names, cname) != -1) { adaptorNIO->et_idx_bcasts_out = ii+1; adaptorNIO->et_nfound++; } } } my_free(ctrNames); } } } #endif } }