21 #include <linux/ethtool.h> 22 #include <linux/sockios.h> 23 #include <sys/ioctl.h> 24 #include <sys/socket.h> 39 strncpy(this->
ifr.ifr_name, aName, IF_NAMESIZE);
45 this->fd = socket(AF_INET, SOCK_DGRAM, 0);
47 perror(
"Ethtool: Error opening socket");
56 result = close(this->fd);
57 }
while (result == -1 && errno == EINTR);
59 perror(
"Ethtool: Error closing socket");
76 ifr.ifr_ifindex = this->
ifInfo_.size() + 1;
77 int val = ioctl(this->
socketfd_.
fd, SIOCGIFNAME, &ifr);
80 ifr.ifr_name[IF_NAMESIZE - 1] =
'\0';
81 this->
ifInfo_.emplace_back(ifr.ifr_name);
87 for (
size_t i = 0; i < this->
ifInfo_.size(); i++) {
88 this->
ifInfo_[i].ifr.ifr_data = driverInfo.raw();
89 if (ioctl(this->
socketfd_.
fd, SIOCETHTOOL, &this->ifInfo_[i].ifr) == 0)
90 this->
ifInfo_[i].driver = driverInfo->driver;
92 this->
ifInfo_[i].driver =
"unknown";
95 ssetInfo->sset_mask = 1 << ETH_SS_STATS;
96 this->
ifInfo_[i].ifr.ifr_data = ssetInfo.
raw();
97 if (ioctl(this->
socketfd_.
fd, SIOCETHTOOL, &this->ifInfo_[i].ifr) == 0) {
98 size_t count = ssetInfo->sset_mask ? ssetInfo->data[0] : 0;
99 this->
ifInfo_[i].fieldCount = count;
105 gstrings->string_set = ETH_SS_STATS;
106 gstrings->len = count;
107 this->
ifInfo_[i].ifr.ifr_data = gstrings.raw();
108 if (ioctl(this->
socketfd_.
fd, SIOCETHTOOL, &this->ifInfo_[i].ifr) == 0) {
109 for (
size_t j = 0; j < gstrings->len; j++) {
110 gstrings->data[(j + 1) * ETH_GSTRING_LEN - 1] =
'\0';
111 this->
ifInfo_[i].fieldNames.emplace_back(this->
parseEthtoolString(reinterpret_cast<char*>(&gstrings->data[j * ETH_GSTRING_LEN])));
114 std::iota(this->
ifInfo_[i].fieldIndexes.begin(), this->
ifInfo_[i].fieldIndexes.end(), 0);
115 if (this->
ifInfo_[i].driver ==
"ixgbe")
118 perror(
"Ethtool: cannot read device stats strings");
122 perror(
"Ethtool: cannot read device stats count");
125 this->
ifInfo_[i].ifr.ifr_data =
nullptr;
130 std::string indexString =
"";
131 size_t index = ethtoolString.find_first_of(
"0123456789");
132 if (index != std::string::npos) {
134 while (std::isdigit(ethtoolString[index + count])) {
135 indexString.append(ethtoolString, index + count, 1);
138 if (index + count >= ethtoolString.size())
141 ethtoolString.replace(index, count,
"i");
144 bool wasCapitalized =
false;
145 for (
size_t i = 0; i < ethtoolString.size(); i++) {
146 if (!std::isalnum(ethtoolString[i]) && ethtoolString[i] !=
'_') {
147 if (i > 0 && ethtoolString[i - 1] !=
'_') {
148 ethtoolString[i] =
'_';
150 ethtoolString.erase(i, 1);
154 else if (std::isupper(ethtoolString[i])) {
155 if (i > 0 && ethtoolString[i - 1] !=
'_' && std::islower(ethtoolString[i - 1]) && !wasCapitalized) {
156 ethtoolString.insert(i,
"_");
159 ethtoolString[i] = std::tolower(ethtoolString[i]);
160 wasCapitalized =
true;
162 wasCapitalized =
false;
164 while (ethtoolString.back() ==
'_')
165 ethtoolString.erase(ethtoolString.size() - 1, 1);
166 while (ethtoolString.front() ==
'_')
167 ethtoolString.erase(0, 1);
170 ret.
name = std::move(ethtoolString);
171 if (!indexString.empty())
172 ret.
index = std::move(indexString);
178 ifInfo.
ifr.ifr_data = channels.raw();
182 for (
size_t i = 0; i < ifInfo.
fieldNames.size(); i++) {
183 const char* name = ifInfo.
fieldNames[i].name.c_str();
184 if ((name[0] ==
'r' || name[0] ==
't') && std::strncmp(name + 1,
"x_queue_i_", 10) == 0 && ifInfo.
fieldNames[i].index.has_value() && std::stoull(ifInfo.
fieldNames[i].index.value()) >= channels->combined_count)
190 perror(
"Ethtool: cannot read device channels");
193 ifInfo.
ifr.ifr_data =
nullptr;
199 for (
const auto& info : this->
ifInfo_)
200 count += info.fieldCount;
208 size_t baseIndex = 0;
209 std::vector<size_t> indexes;
210 for (
size_t i = 0; i < this->
ifInfo_.size(); i++) {
212 auto itr = std::find_if(this->
ifInfo_[i].fieldIndexes.begin(), this->
ifInfo_[i].fieldIndexes.end(), [&](
const auto& a) {
213 return this->
ifInfo_[i].fieldNames[a].name == fieldName[3];
215 while (itr != this->
ifInfo_[i].fieldIndexes.end()) {
216 indexes.push_back(std::distance(this->
ifInfo_[i].fieldIndexes.begin(), itr) + baseIndex);
220 itr = std::find_if(itr, this->
ifInfo_[i].fieldIndexes.end(), [&](
const auto& a) {
221 return this->
ifInfo_[i].fieldNames[a].name == fieldName[3];
225 baseIndex += this->
ifInfo_[i].fieldCount;
236 for (
size_t i = 0; i < this->
ifInfo_.size(); i++) {
238 auto& fieldName = this->
ifInfo_[i].fieldNames[this->
ifInfo_[i].fieldIndexes[index]];
241 name.push_back(fieldName.index.value());
248 index -= this->
ifInfo_[i].fieldCount;
254 std::vector<FieldInfo> info;
256 for (
size_t i = 0; i < count; i++)
257 info.push_back(this->fieldInfoAtIndex(i));
259 std::sort(info.begin(), info.end(), [&](
const auto& a,
const auto& b) {
267 if (cmp == 0 && a.name.size() > 4 && b.name.size() > 4) {
275 auto last = std::unique(info.begin(), info.end(), [&](
const auto& a,
const auto& b) {
276 return (a.name[1] == b.name[1] && a.name[3] == b.name[3]);
278 info.erase(last, info.end());
280 for (
auto& field : info) {
281 for (
const auto& dynamicIndex: field.dynamicIndexes)
290 for (
size_t i = 0; i < this->
ifInfo_.size(); i++) {
293 else if (!interests.
isSet(i)) {
295 current += this->
ifInfo_[i].fieldCount;
299 this->
ifInfo_[i].ifr.ifr_data = this->
ifInfo_[i].statsValues.raw();
300 if (ioctl(this->
socketfd_.
fd, SIOCETHTOOL, &this->ifInfo_[i].ifr) == 0) {
301 for (
size_t j: this->
ifInfo_[i].fieldIndexes) {
306 perror(
"Ethtool: cannot read device stats values");
310 this->
ifInfo_[i].ifr.ifr_data =
nullptr;
316 for (
size_t i = 0; i < this->
ifInfo_.size(); i++) {
317 if (!interests.isSet(i))
319 for (
size_t j = 0; j < this->
ifInfo_[i].fieldCount; j++) {
320 *diff =
static_cast<DiffValueType>((*current - *previous) * factor);
Object used to describe a field (or metric)
std::vector< std::string > FieldName
Type used for field names (an array of strings)
Namespace for sources of metrics objects and operations.
std::vector< DataValueType >::const_iterator ConstIterator
Const iterator type of MetricsDataArray.
int64_t DataValueType
Type of fetched raw metrics.
int alphanumCompare(const char *l, const char *r)
Alphanumeric string comparison.
Boolean array to keep track of which fields a source has to fetch metrics for.
std::vector< DiffValueType >::iterator Iterator
Iterator type of MetricsDiffArray.
std::string findUnit(const std::string &name, const std::array< KeyUnit, N > &keyUnitAssociation, const std::string_view &defaultUnit)
Tries to associate a field name with a unit, falling back on the default unit if none matches...
std::vector< IndexAndDescription > dynamicIndexes
Indexes and descriptions of the dynamic parts of the field name.
std::vector< DataValueType >::iterator Iterator
Iterator type of MetricsDataArray.
bool isSet(T index) const
Checks if a specific bit is true.
double DiffValueType
Type of metric variation.