Version 2.3.43 of the kernel saw a major rework of the networking subsystem. The new “softnet” implementation was a great improvement in terms of performance and clean design. It also, of course, brought changes to the network driver interface—though fewer than one might have expected.
First of all, Linux 2.3.14 renamed the network device structure, which
had always been struct device
, to struct net_device
. The new name is certainly more appropriate,
since the structure was never meant to describe devices in general.
Prior to version 2.3.43, the functions
netif_start_queue,
netif_stop_queue, and
netif_wake_queue did not exist. Packet
transmission was, instead, controlled by three fields in the
device
structure, and sysdep.h
implements the three functions using the three fields when compiling
for 2.2 or 2.0.
-
unsigned char start;
This variable indicated that the interface was ready for operations; it was normally set to 1 in the driver’s open method. The current implementation is to call netif_start_queue instead.
-
unsigned long interrupt;
interrupt
was used to indicate that the device was servicing an interrupt—accordingly, it was set to 1 at the beginning of the interrupt handler and to 0 before returning. It was never a substitute for proper locking, and its use has been replaced with internal spinlocks.-
unsigned long tbusy;
When nonzero, this variable indicated that the device could handle no more outgoing packets. Where a 2.4 driver will call netif_stop_queue, older drivers would set
tbusy
to 1. Restarting the queue required settingtbusy
back to 0 and callingmark_bh(NET_BH)
.
Normally, setting tbusy
was sufficient to ensure
that the driver’s hard_start_xmit method would
not be called. However, if the networking system decided that a
transmitter lockup must have occurred, it would call that method
anyway. There was no tx_timeout method before
softnet was integrated. Thus, pre-softnet drivers had to explicitly
check for a call to hard_start_xmit when
tbusy
was set and react accordingly.
The type of the name
field in struct device
was different. The 2.2 version was simply
char *name;
Thus, the storage for the interface name had to be allocated
separately, and name
assigned to point to that
storage. Usually the device name was stored in a static variable
within the driver. The %d
notation for dynamically
assigned interface names was not present in 2.2; instead, if the name
began with a null byte or a space character, the kernel would allocate
the next eth
name. The 2.4 kernel still implements
this behavior, but its use is deprecated. Starting with 2.5, only the
%d
format is likely to be recognized.
The owner
field (and the
SET_MODULE_OWNER
macro) were added in kernel
2.4.0-test11, just before the official stable release. Previously,
network driver modules had to maintain their own use counts.
sysdep.h
defines an empty
SET_MODULE_OWNER
for kernels that do not have it;
portable code should also continue to manage its use count manually
(in addition to letting the networking system do it).
The link state functions (netif_carrier_on and netif_carrier_off) did not exist in the 2.2 kernel. The kernel simply did without that information in those days.
The 2.1 development series also saw its share of changes to the network driver interface. Most took the form of small changes to function prototypes, rather than sweeping changes to the network code as a whole.
Interface statistics were kept in a structure called struct 1enet_statistics
, defined in
<linux/if_ether.h>
. Even non-Ethernet
drivers used this structure. The field names were all the same as the
current struct net_device_stats
, but the
rx_bytes
and tx_bytes
fields
were not present.
The 2.0 kernel handled transmitter lockups in the same way as 2.2 did. There was, however, an additional function:
void dev_tint(struct device *dev);
This function would be called by the driver after a lockup had been cleared to restart the transmission of packets.
A couple of functions had different prototypes.
dev_kfree_skb had a second, integer argument that
was either FREE_READ
for incoming packets (i.e.,
skb
s allocated by the driver) or
FREE_WRITE
for outgoing packets
(skb
s allocated by the networking code). Almost all
calls to dev_kfree_skb in network driver code
used FREE_WRITE
. The nonchecking versions of the
skb
functions (such as
__skb_push) did not exist;
sysdep.h
in the sample code provides emulation
for these functions under 2.0.
The rebuild_header method had a different set of arguments:
int (*rebuild_header) (void *eth, struct device *dev, unsigned long raddr, struct sk_buff *skb);
The Linux kernel also made heavier use of rebuild_header; it did most of the work that hard_header does now. When snull is compiled under Linux 2.0, it builds hardware headers as follows:
int snull_rebuild_header(void *buff, struct net_device *dev, unsigned long dst, struct sk_buff *skb) { struct ethhdr *eth = (struct ethhdr *)buff; memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */ return 0; }
The device methods for header caching were also significantly
different in this kernel. If your driver needs to implement these
functions directly (very few do), and it also needs to work with the
2.0 kernel, see the definitions in
<linux/netdevice.h>
to see how things were
done in those days.
If you look at the source for almost any network driver in the kernel, you will find some boilerplate that looks like this:
#ifdef HAVE_DEVLIST /* * Support for an alternate probe manager, * which will eliminate the boilerplate below. */ struct netdev_entry netcard_drv = {cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist}; #else /* Regular probe routine defined here */
Interestingly, this code has been around since the 1.1 development series, but we are still waiting for the promised alternate probe manager. It is probably safe to not worry about being prepared for this great change, especially since ideas for how to implement it will likely have changed in the intervening years.
Get Linux Device Drivers, Second Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.