Author Topic: linux, is it possible to get the driver name of a built-in ethernet device?  (Read 4754 times)

0 Members and 5 Guests are viewing this topic.

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
I'm writing a rather peculiar software, that runs in an equally peculiar scenario

Basically I can't have kernel modules, all the devices are "kernel-builtin", and there are about two Tulip cards, each quad-ethernet, plus two more VIA, also quad-ethernet

There are too many network ports ... but that's not the problem, when it comes to the fact that only the Tulips offer "CPU offloading" and are capable of working in extra-jumbo.

I work with several kernels, some of the old 4 family, some of the 5 family, some of the 6 family, all compiled for the same target, even if not always both types of network cards are installed.

Sometimes only the Tulips, sometimes only the VIAs, sometimes there are also some 3Coms.

To make it short, and for how my software works, I would need to know which driver is associated with a network interface.

eth0 <---- SoC built-in
eth1 <---- Tulips? Via? 3Com? Other? Which kernel driver?
...
ethN <---- Tulips? Via? 3Com? Other? Which kernel driver?

How can I get this information?

Code: [Select]
# ls /sys/class/net/eth*/
I looked into something like this, but is seems it doesn't export anything about the kernel driver.


As a temporary solution, I identify the driver by the mac-address.
That is, I made a table of all the mac-addresses of all the network cards used.

But it is not practical .... at the moment it is a file with about 242 lines!
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 11140
  • Country: fi
This problem was recognized... at least 10 years ago, if not more? We got deterministic interface names, which irritated many in the beginning, but has obvious advantages.

If you are forced to use 15-year old versions, maybe you could take a look how it's implemented more recently and apply a patch?
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
driver_name = get_it(interface name)

How?
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
This problem was recognized... at least 10 years ago, if not more? We got deterministic interface names, which irritated many in the beginning, but has obvious advantages.

If you are forced to use 15-year old versions, maybe you could take a look how it's implemented more recently and apply a patch?

Don't troll, please.
Otherwise, enjoy my ignore list, again.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 9166
  • Country: de
  • A qualified hobbyist ;)
ethtool -i eth0 | grep driver
 
The following users thanked this post: DiTBho

Offline Traceless

  • Frequent Contributor
  • **
  • Posts: 359
  • Country: de
Hi DiTBho,

you should be able to get the information you need by using the command lshw -C network. The output also contains some information that you do not require. If you want to filter those you could use lshw -C network | grep -E "(product|configuration|logical name):". The command also supports alternative output formats like JSON (-json), HTML (-html) or XML (-xml) for easier processing with external tools. If you don't want to rely on lshw being installed or run it as external command you could take a look at its source code and replicate the portions required in your program.
 
The following users thanked this post: DiTBho

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
A solution like this doesn't see to work with "network devices", as not listed in /dev.

I am tempted to hack the kernel to extract the information I need when the kernel driver registers itself and gets its interface name.

It would nice
Dev name -> kernel driver name
E.g.
Eth0 -> ppc4xx-net
Eth1 -> tulip
...
Eth9 -> via

Exported in ? /proc/net/name_driver ?

But umm, I have to carefully think about this hack.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 30115
  • Country: nl
    • NCT Developments
Use the MAC address but filter by manufacturer. Don't use the entire MAC address!
« Last Edit: May 31, 2025, 08:16:30 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 
The following users thanked this post: DiTBho

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
You can obtain the kernel driver name for ethX using
    readlink /sys/class/net/ethX/device/driver/module | sed -e 's,^.*/,,'
or in your own code, using readlinkat() and skipping everything up to and including the last slash, if it has any slashes (it should).

A solution like this doesn't see to work with "network devices", as not listed in /dev.
The device path for Ethernet devices is /sys/class/net/device, so the key thing would be to see what your
    udevadm info /sys/class/net/eth0
and
    udevadm info /sys/class/net/eth1
so that we can see what you can use in an udev rule to set the device names (just by assigning to NAME).

Note that the above does apply even if you use eudev instead of systemd-subsumed udev.

If you use mdev or an old-style fixed /dev, then populate /dev/mactab with
    dev-name mac-address
and before bringing up any network interfaces, run /sbin/nameif -s (from net-tools package, official Github source mirror).
 
The following users thanked this post: DiTBho

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Code: [Select]
ls /sys/class/net/eth0/device/driver/
0000:00:0a.0/ bind          new_id        remove_id     uevent        unbind

"module" is not there  :-//

I am writing a C application, I need a way to get the information possibly without having to depend on an external program
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
udev rule to set the device names

I forgot: I don't need to "change" the device names, and I can't use udev.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Code: [Select]
# udevadm info /sys/class/net/eth0
P: /devices/pci0000:00/0000:00:0a.0/net/eth0
M: eth0
R: 0
U: net
I: 2
E: DEVPATH=/devices/pci0000:00/0000:00:0a.0/net/eth0
E: SUBSYSTEM=net
E: INTERFACE=eth0
E: IFINDEX=2
E: USEC_INITIALIZED=8738139
E: ID_NET_NAMING_SCHEME=v251
E: ID_NET_NAME_MAC=enx00264a1bf770
E: ID_OUI_FROM_DATABASE=Apple, Inc.
E: ID_NET_NAME_PATH=enp0s10
E: ID_BUS=pci
E: ID_VENDOR_ID=0x10de
E: ID_MODEL_ID=0x0ab0
E: ID_PCI_CLASS_FROM_DATABASE=Network controller
E: ID_PCI_SUBCLASS_FROM_DATABASE=Ethernet controller
E: ID_VENDOR_FROM_DATABASE=NVIDIA Corporation
E: ID_MODEL_FROM_DATABASE=MCP79 Ethernet (Apple iMac 9,1)
E: ID_PATH=pci-0000:00:0a.0
E: ID_PATH_TAG=pci-0000_00_0a_0
E: ID_NET_DRIVER=forcedeth <------------- this one!
E: ID_NET_LINK_FILE=/lib/systemd/network/99-default.link
E: ID_NET_NAME=eth0
(Apple MacMini/Intel-2009)

It works.
But where does it get the driver information from?
I would like to replicate the code in C.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Code: [Select]
# udevadm info /sys/class/net/eth0/
missing option

# uname -r
2.6.39-apple-minimac-G4

does it also work for 2.6 kernels?
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Use the MAC address but filter by manufacturer. Don't use the entire MAC address!

yeah, that's plan-B"  ;D
and it's already ready!

edit:
There is a problem with reprogrammed NICs, anyway.
Things with a on-chip (EEPROM) "reprogrammed" mac-address.
Fake vendor, crazy mac-address, e.g. "deadcafe00"

Umm, and with "firmware defined" mac-address.
e.g. PPC4xx boards with u-boot.
You can change the mac-address from the env console
(envset macaddr deadcafe00), and Linux will simply take what passed from u-boot.

Anyway, these two are extrame examples of hobby stuff.
« Last Edit: May 31, 2025, 10:17:21 pm by DiTBho »
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
udev/eudev is a daemon which receives device events using netlink (socket type) from the kernel.
The udevadm command queries that daemon as to what information was available at the time the event occurred.

Problem is, you don't have anything listening to those events.

Does ethtool -i ethX report the driver:?
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Code: [Select]
/sys/class/net/eth0/device/uevent:DRIVER=forcedeth
(macmini-intel/2009)
Code: [Select]
/sys/class/net/eth0/device/ueventDRIVER=gem
(macmini-pcc/2005)

Code: [Select]
/sys/class/net/eth12/device/uevent:DRIVER=tulip
(zserver with DEC nics)

it sounds, the information I was looking for  ;D ;D ;D
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Monkeh

  • Super Contributor
  • ***
  • Posts: 8817
  • Country: gb
The symlink /sys/class/net/*/device/driver will tell you the driver name just fine. Otherwise, see the ethtool source for inspiration on querying more directly.
 
The following users thanked this post: DiTBho

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
udev/eudev is a daemon which receives device events using netlink (socket type) from the kernel.
The udevadm command queries that daemon as to what information was available at the time the event occurred.

Problem is, you don't have anything listening to those events.

Does ethtool -i ethX report the driver:?

No, I don't have anything listening to these events, especially on embedded profiled machines.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
The symlink /sys/class/net/*/device/driver will tell you the driver name just fine. Otherwise, see the ethtool source for inspiration on querying more directly.

Code: [Select]
grep "gem"  /sys/class/net/eth0/device/driver/0002\:20\:0f.0/uevent
DRIVER=gem

The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Monkeh

  • Super Contributor
  • ***
  • Posts: 8817
  • Country: gb
The symlink /sys/class/net/*/device/driver will tell you the driver name just fine. Otherwise, see the ethtool source for inspiration on querying more directly.

Code: [Select]
grep "gem"  /sys/class/net/eth0/device/driver/0002\:20\:0f.0/uevent
DRIVER=gem

Code: [Select]
$ basename $(readlink /sys/class/net/eno1/device/driver)
e1000e
$ basename $(readlink /sys/class/net/enp3s0/device/driver)
r8169
$ basename $(readlink /sys/class/net/eth0/device/driver)
e1000e

Does not require determining any further path.
 
The following users thanked this post: DiTBho

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Does ethtool -i ethX report the driver:?

just emerged
Code: [Select]
2025-05-31--23-00-53---2025-05-31--23-02-00 - [ sys-apps/ethtool ] - success - [email protected]/13

Code: [Select]
macmini2-intel # ethtool -i eth0
driver: forcedeth <---------- correct!
version: 0.64
firmware-version:
expansion-rom-version:
bus-info: 0000:00:0a.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: no
supports-register-dump: yes
supports-priv-flags: no
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
The symlink /sys/class/net/*/device/driver will tell you the driver name just fine. Otherwise, see the ethtool source for inspiration on querying more directly.

Code: [Select]
grep "gem"  /sys/class/net/eth0/device/driver/0002\:20\:0f.0/uevent
DRIVER=gem

Code: [Select]
$ basename $(readlink /sys/class/net/eno1/device/driver)
e1000e
$ basename $(readlink /sys/class/net/enp3s0/device/driver)
r8169
$ basename $(readlink /sys/class/net/eth0/device/driver)
e1000e

Does not require determining any further path.

Bingo!  :D :D :D :D :D

I have a library, written in C, that implents something similar to "basename"
Code: [Select]
# myfilename_depath "`readlink /sys/class/net/eth0/device/driver`"
forcedeth

And I also have something similar to "readlink".

I can combine them to get the "driver name" without any external support (exec(...)->fork()?) to the main application, which is written in C.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Does ethtool -i ethX report the driver:?

just emerged
Code: [Select]
2025-05-31--23-00-53---2025-05-31--23-02-00 - [ sys-apps/ethtool ] - success - [email protected]/13

Code: [Select]
macmini2-intel # ethtool -i eth0
driver: forcedeth <---------- correct!
(Edited to fix messy description)

Initialize struct ethtool_drvinfo info to zeros, but set info.cmd = ETHTOOL_GDRVINFO.
Initialize struct ifreq req to zeros, fill req.if_name with the network device name (terminated with nul, preferably padded with nuls), and set req.if_data to point to info.
Create a socket using int sockfd = socket(AF_INET, SOCK_DGRAM, 0).
Call ioctl(sockfd, SIOCETHTOOL, &req).
Close the socket using close(sockfd).

The ioctl filled in the info structure, including driver name in info.driver, driver version string in info.version, and so on.

Crude example program:
Code: [Select]
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <stdio.h>
#include <errno.h>

#define  DRIVER_NAMELEN  (1 + sizeof ((struct ethtool_drvinfo *)0)->driver)

int get_driver(char driver[DRIVER_NAMELEN], const char *device) {
    const int               device_len = (device) ? strlen(device) : 0;
    struct ethtool_drvinfo  info;
    struct ifreq            req;
    int                     fd, err;

    memset(driver, 0, DRIVER_NAMELEN);

    memset(&info, 0, sizeof info);
    info.cmd = ETHTOOL_GDRVINFO;

    if (device_len < 1 || (size_t)device_len >= sizeof req.ifr_ifrn.ifrn_name) {
        errno = EINVAL;
        return -1;
    }

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd == -1) {
        return -2;  // errno set by socket()
    }

    memset(&req, 0, sizeof req);
    memcpy(req.ifr_ifrn.ifrn_name, device, device_len);
    req.ifr_data = (void *)&info;
    if (ioctl(fd, SIOCETHTOOL, &req) == -1) {
        err = errno;
        close(fd);
        errno = err;
        return -3;  // errno set by ioctl()
    }

    if (close(fd) == -1) {
        return -4;  // errno set by close()
    }

    memcpy(driver, info.driver, sizeof info.driver);
    return 0;
}

int main(int argc, char *argv[]) {
    const char *const arg0 = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "this";

    if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", arg0);
        fprintf(stderr, "       %s ethernet-device\n", arg0);
        fprintf(stderr, "\n");
        fprintf(stderr, "This program outputs the driver name for the given net device.\n");
        fprintf(stderr, "\n");
        return EXIT_SUCCESS;
    }

    char driver[DRIVER_NAMELEN];
    int result = get_driver(driver, argv[1]);
    if (result) {
        fprintf(stderr, "Error %d: %s.\n", -result, strerror(errno));
        return EXIT_FAILURE;
    }

    printf("%s\n", driver);
    return EXIT_SUCCESS;
}
« Last Edit: May 31, 2025, 11:43:37 pm by Nominal Animal »
 
The following users thanked this post: DiTBho

Online DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Does ethtool -i ethX report the driver:?

just emerged
Code: [Select]
2025-05-31--23-00-53---2025-05-31--23-02-00 - [ sys-apps/ethtool ] - success - [email protected]/13

Code: [Select]
macmini2-intel # ethtool -i eth0
driver: forcedeth <---------- correct!
In that case, you can use if_nameindex() to get the network interfaces and corresponding indexes.  Then, if you go through them one by one, creating an IP socket, bind it to a specific interface index name using SO_BINDTODEVICE socket option, you can use the SIOCETHTOOL ioctl, with the struct ethtool_drvinfo .cmd field set to ETHTOOL_GDRVINFO.  This will fill the .driver name field.

Excellent!
I wrote a simple draft, it works!
It's nice that there is a way to "query" for information from the kernel about a specific network interface.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 
The following users thanked this post: Nominal Animal

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Note that I edited my post for clarity; I definitely wasn't initially as clear/simple as the actual procedure is!  Apologies for changing the discussion history, though.

It's nice that there is a way to "query" for information from the kernel about a specific network interface.
It does get messy if you want more in-depth driver-specific data, because ethtool is so closely tied to the Linux kernel.

Do note that both nameif and ifconfig can rename an ethernet interface as long as the interface is down, so you can have persistent network/ethernet device names even without dynamic device event support (udev/eudev daemon): just add an init step to do that after all network devices have been probed and drivers loaded, but before any network interfaces are enabled/up'd.  Then you do know all the network devices, too.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf