ethernet_interface_info.cpp
Go to the documentation of this file.
2 #include <linux/ethtool.h>
3 #include <linux/sockios.h>
4 #include <net/if.h>
5 #include <sys/ioctl.h>
6 #include <errno.h>
7 
9  rx_errors_(0),
10  rx_crc_errors_(0),
11  rx_frame_errors_(0),
12  rx_align_errors_(0)
13 {
14  //empty
15 }
16 
18 {
19  this->rx_errors_ -= right.rx_errors_;
20  this->rx_crc_errors_ -= right.rx_crc_errors_;
21  this->rx_frame_errors_ -= right.rx_frame_errors_;
22  this->rx_align_errors_ -= right.rx_align_errors_;
23  return *this;
24 }
25 
27  sock_(-1),
28  n_stats_(0),
29  ethtool_stats_buf_(NULL),
30  rx_error_index_(-1),
31  rx_crc_error_index_(-1),
32  rx_frame_error_index_(-1),
33  rx_align_error_index_(-1)
34 {
35 
36 }
37 
39 {
40  delete[] ethtool_stats_buf_;
41  ethtool_stats_buf_ = NULL;
42  if (sock_ >= 0)
43  close(sock_);
44 }
45 
46 void EthernetInterfaceInfo::initialize(const std::string &interface)
47 {
48  interface_ = interface;
49 
50  // Need network socket to make interface requests ioctls
51  sock_ = socket(AF_INET, SOCK_DGRAM, 0);
52  if (sock_ < 0)
53  {
54  ROS_WARN("Cannot get control socket for ioctls : %s", strerror(errno));
55  return;
56  }
57 
58  // Get initial interface state
60 
61  struct ifreq ifr;
62  memset(&ifr, 0, sizeof(ifr));
63  strncpy(ifr.ifr_name, interface_.c_str(), sizeof(ifr.ifr_name));
64 
65  // Determine number of statictics available from network interface
66  struct ethtool_drvinfo drvinfo;
67  drvinfo.cmd = ETHTOOL_GDRVINFO;
68  ifr.ifr_data = (caddr_t)&drvinfo;
69  int result = ioctl(sock_, SIOCETHTOOL, &ifr);
70  if (result < 0)
71  {
72  ROS_WARN("Cannot get driver information for %s : %s", interface_.c_str(), strerror(errno));
73  return;
74  }
75  n_stats_ = drvinfo.n_stats;
76  if (n_stats_ < 1)
77  {
78  ROS_WARN("No NIC statistics available for %s", interface_.c_str());
79  return;
80  }
81 
82  unsigned strings_len = sizeof(ethtool_gstrings) + n_stats_ * ETH_GSTRING_LEN;
83  char *strings_buf = new char[ strings_len ];
84  memset(strings_buf, 0, strings_len);
85  ethtool_gstrings* strings = (ethtool_gstrings*) strings_buf;
86 
87  strings->cmd = ETHTOOL_GSTRINGS;
88  strings->string_set = ETH_SS_STATS;
89  strings->len = n_stats_;
90  ifr.ifr_data = (caddr_t) strings;
91  result = ioctl(sock_, SIOCETHTOOL, &ifr);
92  if (result < 0)
93  {
94  ROS_WARN("Cannot get statistics strings for %s : %s", interface_.c_str(), strerror(errno));
95  delete[] strings_buf;
96  return;
97  }
98 
99  for (unsigned i=0; i<n_stats_; ++i)
100  {
101  if (false)
102  {
103  char s[ETH_GSTRING_LEN+1];
104  strncpy(s, (const char*) &strings->data[i * ETH_GSTRING_LEN], ETH_GSTRING_LEN);
105  s[ETH_GSTRING_LEN] = '\0';
106  ROS_WARN("Stat %i : %s", i, s);
107  }
108  const char *stat_name = (const char*) &strings->data[i * ETH_GSTRING_LEN];
109  if (strncmp("rx_errors", stat_name, ETH_GSTRING_LEN) == 0)
110  {
111  rx_error_index_ = i;
112  }
113  else if (strncmp("rx_crc_errors", stat_name, ETH_GSTRING_LEN) == 0)
114  {
116  }
117  else if (strncmp("rx_frame_errors", stat_name, ETH_GSTRING_LEN) == 0)
118  {
120  }
121  else if (strncmp("rx_align_errors", stat_name, ETH_GSTRING_LEN) == 0)
122  {
124  }
125  }
126 
127  // Everything is complete, allocate memory for ethtool_stats_ buffer
128  // Since not all NICs provide ethtool statistics, use the presence of
129  // ethtool_stats_ buffer to indicate initialization was a success.
130  unsigned ethtool_stats_buf_len = sizeof(struct ethtool_stats) + n_stats_ * sizeof(uint64_t);
131  ethtool_stats_buf_ = new char[ethtool_stats_buf_len];
132 
134  {
135  // Don't run if we can't get initial statitics
136  ROS_WARN("Error collecting intial ethernet interface statistics");
137  delete[] ethtool_stats_buf_;
138  ethtool_stats_buf_ = NULL;
139  }
140 }
141 
142 
144 {
145  struct ifreq ifr;
146  memset(&ifr, 0, sizeof(ifr));
147  strncpy(ifr.ifr_name, interface_.c_str(), sizeof(ifr.ifr_name));
148 
149  if (ioctl(sock_, SIOCGIFFLAGS, &ifr) < 0) {
150  ROS_WARN("Cannot get interface flags for %s: %s", interface_.c_str(), strerror(errno));
151  return false;
152  }
153 
154  state.up_ = bool(ifr.ifr_flags & IFF_UP);
155  state.running_ = bool(ifr.ifr_flags & IFF_RUNNING);
156  return true;
157 }
158 
159 
161 {
162  if (!ethtool_stats_buf_)
163  return false;
164 
165  struct ifreq ifr;
166  memset(&ifr, 0, sizeof(ifr));
167  strncpy(ifr.ifr_name, interface_.c_str(), sizeof(ifr.ifr_name));
168 
169  struct ethtool_stats *stats = (struct ethtool_stats *) ethtool_stats_buf_;
170  stats->cmd = ETHTOOL_GSTATS;
171  stats->n_stats = n_stats_;
172  ifr.ifr_data = (caddr_t) stats;
173  if (ioctl(sock_, SIOCETHTOOL, &ifr) < 0)
174  {
175  ROS_WARN("Cannot get NIC stats information for %s : %s", interface_.c_str(), strerror(errno));
176  return false;
177  }
178 
179  if (rx_error_index_ >= 0)
180  {
181  s.rx_errors_ = stats->data[rx_error_index_];
182  }
183  if (rx_crc_error_index_ >= 0)
184  {
185  s.rx_crc_errors_ = stats->data[rx_crc_error_index_];
186  }
187  if (rx_frame_error_index_ >= 0)
188  {
189  s.rx_frame_errors_ = stats->data[rx_frame_error_index_];
190  }
191  if (rx_align_error_index_ >= 0)
192  {
193  s.rx_align_errors_ = stats->data[rx_align_error_index_];
194  }
195 
196  return true;
197 }
198 
200 {
201  d.add("Interface", interface_);
202 
203  // TODO : collect and publish information on whether interface is up/running
204  InterfaceState state;
205  if (getInterfaceState(state))
206  {
207  if (!state.running_ && last_state_.running_)
208  {
210  }
211 
212  if (state.up_ && !state.running_)
213  {
214  d.mergeSummary(d.ERROR, "No link");
215  }
216  else if (!state.up_)
217  {
218  d.mergeSummary(d.ERROR, "Interface down");
219  }
220 
221  d.addf("Interface State", "%s UP, %s RUNNING", state.up_?"":"NOT", state.running_?"":"NOT");
222  last_state_ = state;
223  }
224  else
225  {
226  d.add("Iface State", "ERROR");
227  }
228  d.add("Lost Links", lost_link_count_);
229 
230  EthtoolStats stats;
231  bool have_stats = getEthtoolStats(stats);
232  stats-=orig_stats_; //subtract off orignal counter values
233 
234  if (have_stats && (rx_error_index_>=0))
235  d.addf("RX Errors", "%llu", stats.rx_errors_);
236  else
237  d.add( "RX Errors", "N/A");
238 
239  if (have_stats && (rx_crc_error_index_>=0))
240  d.addf("RX CRC Errors", "%llu", stats.rx_crc_errors_);
241  else
242  d.add( "RX CRC Errors", "N/A");
243 
244  if (have_stats && (rx_frame_error_index_>=0))
245  d.addf("RX Frame Errors", "%llu", stats.rx_frame_errors_);
246  else
247  d.add( "RX Frame Errors", "N/A");
248 
249  if (have_stats && (rx_align_error_index_>=0))
250  d.addf("RX Align Errors", "%llu", stats.rx_align_errors_);
251  else
252  d.add( "RX Align Errors", "N/A");
253 
254 }
unsigned lost_link_count_
Number of time master link went down.
int sock_
network socket for making ioctl requests
bool getInterfaceState(InterfaceState &state)
Get state (up,running) of interface.
void initialize(const std::string &interface)
XmlRpcServer s
std::string interface_
name of network interface (for example : eth0)
#define ROS_WARN(...)
void addf(const std::string &key, const char *format,...)
unsigned n_stats_
Number of stats available from ethtool ioctl.
char * ethtool_stats_buf_
buffer for NIC statistic values
EthtoolStats orig_stats_
Orignal statistics counts when initialize() was called.
void mergeSummary(unsigned char lvl, const std::string s)
EthtoolStats & operator-=(const EthtoolStats &right)
void add(const std::string &key, const T &val)
void publishDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &d)
Collect and append ethernet interface diagnostics.
bool getEthtoolStats(EthtoolStats &stats)
Get ethtool stats from interface.


ethercat_hardware
Author(s): Rob Wheeler , Derek King
autogenerated on Thu Mar 4 2021 03:10:21