The ‘net_device’ structure A look at the main kernel-object network interface controller

Download Report

Transcript The ‘net_device’ structure A look at the main kernel-object network interface controller

The ‘net_device’ structure
A look at the main kernel-object
concerned with a Linux system’s
network interface controller
‘data consolidation’
• Experienced software developers usually
employ a ‘locality of reference’ strategy to
simplify design and maintenance of code
• This principle says: Things which logically
are related should be kept together
• Accordingly, all the information that the
system needs to keep track of about a
network interface is put into a single struct
‘struct net_device’
dev_base_head
next
prev
struct net_device
lo
About 90 separate
fields belong to
each ‘net_device’
member of this
doubly-linked list
struct net_device
eth0
struct net_device
eth1
A few examples…
struct net_device
{
char
name[ IFNAMSIZ ];
int
ifindex;
\
/* inteface index */
unsigned int
mtu;
/* maximum transmission unit */
unsigned char
dev_addr[ MAX_ADDR_LEN ]; /* hardware address */
void
*ip_pointer;
/* points to IF’s IPv4 specific data */
unsigned int
flags;
unsigned long
trans_start;
/* time (in jiffies) of last transmission */
struct net_device_stats
stats;
/* a default set of device statistics */
…
// some function-pointers (i.e., these are ‘virtual’ functions)
int
(*open)( struct net_device * );
int
(*stop)( struct net_device * );
int
(*hard_start_xmit)( struct sk_buff *, struct net_device * );
int
(*get_stats)( struct net_device * );
…
};
An analogy?
• The ‘struct net_device’ kernel-objects play a
similar role for network device-drivers as is
played by ‘struct file_operations’ objects with
regard to character device-drivers…
struct file_operations
open()
release()
write()
read()
llseek()
ioctl()
…
struct net_device
open()
stop()
hard_start_xmit()
get_stats()
set_mac_address()
do_ioctl()
…
• This analogy isn’t perfect (i.e., key differences)
‘struct net_device_stats’
• Notice that the ‘net_device’ object contains
a sub-structure for storing device statistics
struct net_device_stats
{
unsigned long
unsigned long
};
rx_packets;
tx_packets;
/* total packets received */
/* total packets transmitted */
unsigned long
unsigned long
rx_bytes; /* total bytes received */
tx_bytes; /* total bytes transmitted */
unsigned long
unsigned long
…
rx_errors; /* bad packets received */
tx_errors; /* packet transmit problems */
‘struct sk_buff’
• Notice that the ‘net_device’ object also has
a member-field which can hold a pointer to
to a kernel-object of type ‘struct sk_buff’
struct sk_buff
skb
packet
data
Kernel’s header-files
• The kernel is written in C (with occasional
uses of some ‘inline’ assembly language)
• All the source-code for our Linux kernel is
in this system directory: </usr/src/linux>
• Most header-files are in <…/include/linux>
• Those header-files that are CPU-specific
are in <…/include/asm>
Our directory tree…
/
sbin
bin
usr
include
ifconfig
…
lsmod
insmod
rmmod
…
ping
…
cat
echo
ls
vi
dmesg
…
home
src
web
linux
include
linux
cruse
asm
cs686
netdevice.h
if.h
…
module.h
pci.h
…
…
io.h
uaccess.h
unistd.h
…
our
course
demos
<linux/netdevice.h>
• This is the header-file where you will find
the ‘struct net_device’ definition (and the
‘struct net_device_stats’ definition as well)
• And if you want to see how ‘struct sk_buff’
is defined, then look in <linux/skbuff.h>
• NOTE: The kernel developers often move
structure-definitions to different headers in
new versions of the kernel source-code
Our ‘netdevs.c’ module
• We can create a Loadable Kernel Module
that lets us see current information stored
in the kernel’s data-structures
• Our example-module ‘netdevs.c’ does this
• It needs a special command-sequence to
be compiled, then a special command to
be installed as a ‘live’ add-on our running
Linux operating system’s kernel
‘mmake.cpp’
• You can download this utility-program from
our cs686 website and compile it with g++,
like this:
$ cp /home/web/cruse/cs686/mmake.cpp .
$ g++ mmake.cpp –o mmake
• Then you can use it to automate the steps
required for compiling an LKM, like this:
$ ./mmake netdevs
‘/sbin/insmod’
• When you have compiled our ‘netdevs.c’
source-file, you will have a kernel-object
file named ‘netdevs.ko’ and you can use
the ‘insmod’ command to install it:
$ /sbin/insmod netdevs.ko
• When it is installed, this LKM creates a
pseudo-file (in the ‘/proc’ directory) that
you can send to your screen with ‘cat’:
$ cat /proc/netdevs
‘/sbin/rmmod’
• If you decide you would like to modify the
output from your ‘/proc/netdevs’ file, you
can remove ‘netdevs.ko’ from the kernel,
edit the module’s source-code, recompile
the ‘netdevs.c’ file with ‘mmake’, and then
install the new version of ‘netdevs.ko’:
$ /sbin/rmmod netdevs.ko
In-class exercise #1
• Modify the output shown by ‘/proc/netdevs’
so that the current state of each interface
(i.e., UP or DOWN) will get displayed
• HINT: The kernel uses a status-bit in the
‘flags’ field of a ‘struct net_device’ object
to keep track of whether the device is now
‘up’ or ‘down’ (compare ‘/sbin/ifconfig –a)
• Look in the header-file <linux/if.h> to find
out how bits of the ‘flags’ field are used
Two coding approaches…
• One way to write your solution for in-class
exercise #1 is to add a line like this:
if ( dev->flags & IFF_UP )
len += sprintf( buf+len, “UP” );
else
len += sprintf( buf+len, “DOWN “ );
• But a different solution which produces the
same effect avoids the ‘if-else’ construct:
char
*state[ 2 ] = { “DOWN”, “UP” };
// an array of string-pointers
…
len += sprintf( buf+len, “%s”, state[ dev->flags & IFF_UP ] );
…
In-class exercise #2
• Look at the output produced when you
execute the Linux ‘ifconfig’ program
• Choose some added item of information
about our station’s network interfaces
(from the ‘ifconfig’ output) and see if you
can enhance our ‘netdevs.c’ demo so it’s
pseudo-file will display that extra item of
information (e.g., dev->stats.tx_bytes)