Skip to content

Instantly share code, notes, and snippets.

@rcgoodfellow
Created April 27, 2016 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rcgoodfellow/ed1d67069dd92eaa638da8070ed6b7a6 to your computer and use it in GitHub Desktop.
Save rcgoodfellow/ed1d67069dd92eaa638da8070ed6b7a6 to your computer and use it in GitHub Desktop.
using udev to get physical ethernet device info
/* -----------------------------------------------------------------------------
* 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