In addition to the
net_device struct within the kernel, network drivers also have their own private or device-specific struct which stores stats unique to the individual hardware.
The name of the struct varies for each device type, however the location remains the same, right after
net_device:
linux-2.6.32-358.14.1.el6.x86_64/include/linux/netdevice.h
/**
* netdev_priv - access network device private data
* @dev: network device
*
* Get network device private data
*/
static inline void *netdev_priv(const struct net_device *dev)
{
return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
}
A search in cscope for
netdev_priv will show you many functions within drivers which update the priv structure via pointers, for example this one in
e1000_main.c:
struct e1000_adapter *adapter = netdev_priv(netdev);
So, given that we know
what the device-specific struct is called, and
where the device-specific private struct is, how do you find it and read it?
We'll need the ability to read kernel memory using
crash, either run on a live system, or in a vmcore captured with kdump:
crash /usr/lib/debug/lib/modules/2.6.32-358.14.1.el6.x86_64/vmlinux /var/crash/2013-08-26/vmcore
We'll also need the debugging symbols for the driver in question:
crash> mod -s e1000 /usr/lib/debug/lib/modules/2.6.32-358.14.1.el6.x86_64/kernel/drivers/net/e1000/e1000.ko.debug
MODULE NAME SIZE OBJECT FILE
ffffffffa01550e0 e1000 170678 /usr/lib/debug/lib/modules/2.6.32-358.14.1.el6.x86_64/kernel/drivers/net/e1000/e1000.ko.debug
The
net command will show you the network devices in the system:
crash> net
NET_DEVICE NAME IP ADDRESS(ES)
ffff88007e76b820 lo 127.0.0.1
ffff8800372c0020 eth0 192.168.1.126
We can then cast
net_device against this to see the in-kernel device struct:
crash> net_device 0xffff8800372c0020
struct net_device {
name = "eth0\000\000\060:03.0\000\000\000",
...
But we want to get
after this struct and cast it against the struct in the driver.
We need to know how big
net_device is:
crash> struct -o net_device
struct net_device {
...
}
SIZE: 1728
We then find the
net address plus the size of
net_device:
crash> px 0xffff8800372c0020+1728
$1 = 0xffff8800372c06e0
We can now cast the device-specific private struct against this new address:
crash> e1000_adapter 0xffff8800372c06e0
struct e1000_adapter {
vlgrp = 0x0,
mng_vlan_id = 65535,
bd_number = 0,
rx_buffer_len = 1522,
...
and we're done!