Created
April 27, 2016 21:55
-
-
Save rcgoodfellow/ed1d67069dd92eaa638da8070ed6b7a6 to your computer and use it in GitHub Desktop.
using udev to get physical ethernet device info
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ----------------------------------------------------------------------------- | |
* This code is an example of how to use udev on linux to get physical | |
* network interfaces and find out information about them | |
* | |
* compiling: | |
* c++ -std=c++11 udev_example.cxx -o udev_example -ludev | |
* | |
* ---------------------------------------------------------------------------*/ | |
#include <iostream> | |
#include <vector> | |
#include <stdexcept> | |
#include <libudev.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <libgen.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <sys/ioctl.h> | |
#include <linux/sockios.h> | |
#include <linux/ethtool.h> | |
#include <linux/wireless.h> | |
using namespace std; | |
struct Ifx | |
{ | |
Ifx(string name, size_t mbps) : name{name}, mbps{mbps} {} | |
const string name; | |
size_t mbps{0}; | |
}; | |
int main() | |
{ | |
vector<Ifx> ixs; | |
//initailize udev data structures | |
udev *udev = udev_new(); | |
if(udev == nullptr) { throw runtime_error{"cant create udev"}; } | |
udev_enumerate *enumerate = udev_enumerate_new(udev); | |
//enumerate all devices in the 'net' subsystem | |
udev_enumerate_add_match_subsystem(enumerate, "net"); | |
udev_enumerate_scan_devices(enumerate); | |
udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); | |
udev_list_entry *dev_list_entry; | |
udev_list_entry_foreach(dev_list_entry, devices) { | |
//get the device path for each found device | |
const char *path = udev_list_entry_get_name(dev_list_entry); | |
//skip virtual devices | |
if(string(path).find("virtual") != string::npos) continue; | |
//extract just the name of the device from the path | |
path = basename(const_cast<char*>(path)); | |
//get the link speed capability -- by asking the kernel through an ethtool | |
//ioctl request | |
ifreq ifr; | |
strncpy(ifr.ifr_name, path, sizeof(ifr.ifr_name)); | |
ethtool_cmd edata; | |
edata.cmd = ETHTOOL_GSET; | |
ifr.ifr_data = reinterpret_cast<char*>(&edata); | |
int sock = socket(PF_INET, SOCK_DGRAM, 0); | |
if(sock < 0) { throw runtime_error{"cant create socket"}; } | |
//not worried about wireless cards at the moment | |
iwreq iwr; | |
strncpy(iwr.ifr_name, path, sizeof(iwr.ifr_name)); | |
if( ioctl(sock, SIOCGIWNAME, &iwr) == 0 ) | |
{ | |
continue; | |
} | |
int rc = ioctl(sock, SIOCETHTOOL, &ifr); | |
close(sock); | |
if(rc < 0 ) | |
{ | |
throw runtime_error{"failed to get ethtool data for " + string(path)}; | |
} | |
//interpret the speed | |
size_t speed{0}; | |
if(edata.supported & SUPPORTED_10000baseT_Full) { speed = 10000; } | |
else if(edata.supported & SUPPORTED_1000baseT_Full) { speed = 1000; } | |
else if(edata.supported & SUPPORTED_100baseT_Full) { speed = 100; } | |
else if(edata.supported & SUPPORTED_10baseT_Full) { speed = 10; } | |
ixs.push_back(Ifx{path, speed}); | |
} | |
udev_enumerate_unref(enumerate); | |
udev_unref(udev); | |
for(const Ifx & i : ixs) | |
cout << i.name << ": " << i.mbps << endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment