170 likes | 186 Views
Discover the main kernel object responsible for managing a Linux system's network interface controller. Learn how experienced software developers utilize the locality of reference strategy to simplify code design and maintenance.
E N D
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 struct net_device struct net_device lo eth0 eth1 About 90 separate fields belong to each ‘net_device’ member of this doubly-linked list
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… • This analogy isn’t perfect (i.e., key differences) struct file_operations struct net_device open() release() write() read() llseek() ioctl() … open() stop() hard_start_xmit() get_stats() set_mac_address() do_ioctl() …
‘struct net_device_stats’ • Notice that the ‘net_device’ object contains a sub-structure for storing device statistics struct net_device_stats { unsigned long rx_packets; /* total packets received */ unsigned long tx_packets; /* total packets transmitted */ unsigned long rx_bytes; /* total bytes received */ unsigned long tx_bytes; /* total bytes transmitted */ unsigned long rx_errors; /* bad packets received */ unsigned long 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 home include src web ifconfig … lsmod insmod rmmod … linux ping … cat echo ls vi dmesg … include cruse linux 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: • But a different solution which produces the same effect avoids the ‘if-else’ construct: if ( dev->flags & IFF_UP ) len += sprintf( buf+len, “UP” ); else len += sprintf( buf+len, “DOWN “ ); 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)