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)