- Brief introduction
- The network interface is the third class of standard Linux devices, and this chapter describes how the network interface interacts with the rest of the kernel.
- The network interface must register itself with a specific kernel data structure in case it is called when the packet is exchanged with the outside world.
- There is no point in the use of common file operations on network interfaces, so it is not possible to embody Unix's "Everything is a file" idea.
- Network driver asynchronous packets from the outside world
- The network device asks the kernel to packets the externally acquired data to the kernel.
- The network subsystem in the Linux kernel is designed to be completely protocol agnostic
- The use of the term "octet" in the network World refers to a set of 8 bits of data, which is the smallest unit that can be understood by network devices and protocols
- A protocol header (header) is a series of bytes in a packet that passes through different layers of the network subsystem
- Connect to the kernel
- LOOPBACK.C, Plip.c and E100.C
- The
- device registration
- driver inserts a data structure into the global network device chain list for each newly detected interface
- <linux/netdevice.h>
- struct net_device< /li>
- struct net_device *alloc_netdev (int sizeof_priv, const char *name, void (*setup) (struct net_device *));
- name is the name of the interface, which can use a format similar to%d in printf, and the kernel will replace%d
with the next available interface number
- <linux/etherdevie.h>
- struct net_device *alloc_etherdev (int sizeof_priv);
- Fibre Channel devices using Alloc_fcdev (<linux/fcdevice.h>)
- FDDI devices using Alloc_fddidev (<linux/ fddidevice.h>)
- Token Ring device using Alloc_trdev (<linux/trdevice.h>)
- register_netdev function
- Initialize each device
- Example
- Ether_setup (Dev);
- Dev->open = open_function;
- Dev->stop = release_function;
- Dev->set_config = config_function;
- Dev->hard_start_xmid = tx_function;
- Dev->do_ioctl = ioctl_function;
- Dev->get_stats = stats_function;
- Dev->rebuild_header = rebuild_header_function;
- Dev->hard_header = header_function;
- Dev->tx_timeout = tx_timeout_function;
- Dev->watchdog_timo = timeout;
- Dev->flags |= Iff_noarp;
- Dev->features |= netif_f_no_csum;
- Dev->hard_header_cache = NULL;
- Priv = Netdev_priv (dev);
- Unloading of modules
- The Unregister_netdev function removes the interface from the system
- The Free_netdev function returns the NET_DEVICE structure to the system
- Net_device Structural Details
- Global information
- Char Name[ifnamsiz];
- unsigned long state;
- struct Net_device *next;
- Int (*init) (struct net_device *dev);
- Hardware information
- unsigned long rmem_end;
- unsigned long rmem_start;
- unsigned long mem_end;
- unsigned long mem_start;
- unsigned long base_addr;
- unsigned char IRQ;
- unsigned char if_port;
- unsigned char DMA;
- Interface information
- Drivers/net/net_init.c
- void Ltalk_setup (struct net_device *dev);
- void Fs_setup (struct net_device *dev);
- void Fddi_setup (struct net_device *dev);
- void Hippi_setup (struct net_device *dev);
- void Tr_setup (struct net_device *dev);
- unsigned short hard_header_len;
- For the Ethernet interface, this value is 14
- Unsigned MTU;
- Maximum Transmission Unit, Ethernet MTU is 1500 octet
- unsigned long Tx_queue_len;
- unsigned short type;
- ARP uses the type member to determine the type of hardware address supported by the interface
- <linux/if_arp.h>
- unsigned char addr_len;
- unsigned char Broadcast[max_addr_len];
- unsigned char Dev_addr[max_addr_len];
- unsigned short flags;
- int features;
- The flag member is a bitmask
- iff_ prefix denotes "interface flag", valid flags defined in <linux/if.h>
- Device method
- Device methods for network interfaces can be divided into two types: basic and optional
- Basic methods
- Int (*open) (struct net_device *dev);
- Int (*stop) (struct net_device *dev);
- Int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
- Int (*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned l EN);
- Int (*rebuild_header) (struct sk_buff *skb);
- void (*tx_timeout) (struct net_device *dev);
- struct Net_device_stats * (*get_stats) (struct net_device *dev);
- Int (*set_config) (struct net_device *dev, struct ifmap *map);
- Optional methods
- Int (*poll) (struct net_device *dev, int *quota);
- void (*poll_controller) (struct net_device *dev);
- Int (*do_ioctl) (struct net_device *dev, struct ifreq *ifr, int cmd);
- void (*set_multicast_list) (struct net_device *dev);
- Int (*set_mac_address) (struct net_device *dev, void *addr);
- Int (*CHANGE_MTU) (struct net_device *dev, int net_mtu);
- Int (*header_cache) (struct neighbour *neigh, struct hh_cache *hh);
- Int (*header_cache_update) (struct Hh_cache *hh, struct net_device *dev, unsigned char *haddr);
- Int (*hard_header_parse) (struct Sk_buff *skb, unsigned char *haddr);
- Tool Members
- unsigned long trans_start;
- unsigned long last_rx;
- int Watchdog_timeo;
- void *priv;
- struct Dev_mc_list *mc_list;
- int mc_count;
- spinlock_t Xmit_lock;
- int Xmit_lock_owner;
- Open and close
- Two tasks are performed when assigning an address to an interface using Ifconfig
- First, address is given via the IOCTL (SIOCSIFADDR)
- The IFF_UP flag in the Dev->flag is then set through the IOCTL (SIOCSIFFLAGS) to open the interface
- For the device, no work is required on the IOCTL (SIOCSIFADDR), and the latter command invokes the device's Open method
- When the interface is closed, Ifconfig uses the IOCTL (SIOSIFFLAGS) to clear the IFF_UP flag, and then calls the Stop function
- In addition, there are a few other steps to follow
- First, copy the hardware address (MAC) from the hardware device to the DEV->DEV_ADDR before the interface is enough to communicate with the outside world
- The transmission queue for the interface should be started
- void Netif_start_queue (struct net_device *dev);
- Packet transmission
- Whenever the kernel transmits a packet, it calls the driver's Hard_start_transmit function to put the data into the outgoing queue
- Each packet processed by the kernel is in a socket buffer structure (SK_BUFF), which is defined in <linux/skbuff.h>
- Pass through the full Hard_start_xmit socket buffer contains the physical packet, and has the complete Transport Layer packet header
- The transport function only performs a consistency check on the packet, and then transmits the data through the hardware-related functions
- If the execution succeeds, HARD_START_XMIT returns 0
- Controlling concurrent transmissions
- Securing concurrent calls with a spin lock in the Net_device structure
- The actual hardware interface is the asynchronous transmission of the packet, and can be used to save the outgoing packet storage space is very limited
- void Netif_wake_queu (struct net_device *dev);
- Notifies the network system to start transmitting packets again
- void netif_tx_disable (struct net_device *dev);
- Prohibit transmission of data packets
- Transfer timeout
- If the current system time exceeds the Trans_start time of the device at least one timeout period, the network layer will eventually call the driver's tx_timeout function
- Scatter/gather I/O
- The process of creating a packet on a network for transfer work, including the process of assembling multiple pieces of data
- If the network interface that is responsible for sending the packet implements decentralized/focused I/O, the packet is not assembled into a large packet
- Scatter/focus I/O can also use the "0 copy" method to transfer network data directly from the user buffer.
- If the NETIF_F_SG flag bit is set within the feature member in the device structure, the kernel passes the scattered packets to the Hard_start_xmit function
- struct SKB_FRAG_STRUCT
- struct page *page;
- __u16 Page_offset;
- __u16 size;
- Receiving of packets
- Receiving data from the network is a bit more complicated than transferring data because a sk_buff must be assigned to the atomic context and passed to the upper layer processing
- The network driver implements two modes of receiving packets: Interrupt Drive Mode and polling method
- Process
- The first step is to allocate a buffer to hold the packet
- Check the return value of the DEV_ALLOC_SKB function
- Once you have a valid SKB pointer, call memcpy to copy the packet data into the buffer
- Finally, the driver updates its statistics counter
- The last step in the process of receiving a packet is performed by NETIF_RX
- Interrupt processing Routines
- Interface interrupts the processor under two possible events
- New Packet Arrival
- The transfer of outgoing packets has been completed
- Typically interrupt routines are interrupted by checking the status registers in the physical device to differentiate between the arrival of new packets and the completion of data transfer
- At the end of the transfer, the statistics are updated and the socket buffers are returned to the system-wide
- DEV_KFREE_SKB (struct sk_buff *skb);
- DEV_KFREE_SKB_IRQ (struct sk_buff *skb);
- Dev_kfree_skb_any (struct sk_buff *skb);
- Do not use receive interrupts
- In order to improve the performance of Linux on broadband systems, network subsystem developers have created another interface based on the polling method (called Napi)
- Stopping the use of interrupts can reduce the load on the processor
- The poll member of the struct Net_device must be set to the driver's polling function
- When the interface notifies the data that the interrupt program cannot process the packet, it also disables receiving interrupts and tells the kernel to start the polling interface from now on.
- Use the NETIF_RECEIVE_SKB function to pass the packet to the kernel instead of using NETIF_RX
- Call Netif_rx_complete to close the polling function
- Change in link state
- Most network technologies that involve actual physical connections provide carrier status information, and the presence of a carrier means that the hardware function is normal
- void Netif_carrier_off (struct net_device *dev);
- void netif_carrier_on (struct net_device *dev);
- int Netif_carrier_ok (struct net_device *dev);
- Used to detect the current carrier status
- Socket buffers
- <linux/skbuff.h>
- Important Members
- struct Net_device *dev
- Union {/* ... */} h;
- Union {/* ... */} NH;
- Union {/* ... */} mac;
- unsigned char *head;
- unsigned char *data;
- unsigned char *tail;
- unsigned char *end;
- unsigned int len;
- unsigned int data_len;
- unsigned char ip_summed;
- unsigned char pkt_type;
- Shinfo (struct sk_buff *skb);
- unsigned int shinfo (SKB)->nr_frags;
- skb_frag_t shinfo (SKB)->frags;
- Functions to manipulate socket buffers
- struct Sk_buff *alloc_skb (unsigned int len, int priority);
- struct Sk_buff *dev_alloc_skb (unsigned int len);
- void Kfree_skb (struct sk_buff *skb);
- void Dev_kfree_skb (struct sk_buff *skb);
- void Dev_kfree_skb_irq (struct sk_buff *skb);
- void Dev_kfree_skb_any (struct sk_buff *skb);
- unsigned char *skb_put (struct sk_buff *skb, int len);
- unsigned char *__skb_put (struct sk_buff *skb, int len);
- unsigned char *skb_push (struct sk_buff *skb, int len);
- unsigned char *__skb_push (struct sk_buff *skb, int len);
- int skb_tailroom (struct sk_buff *skb);
- int skb_headroom (struct sk_buff *skb);
- void Skb_reserve (struct sk_buff *skb, int len);
- unsigned char *skb_pull (struct sk_buff *skb, int len);
- int skb_is_nonlinear (struct sk_buff *skb);
- int Skb_headlen (struct sk_buff *skb);
- void *kmap_skb_frag (skb_frag_t *frag);
- void Kunmap_skb_frag (void *vaddr);
- MAC Address Resolution
- Using ARP in Ethernet
- ARP is maintained by the kernel, and the Ethernet interface does not need to do any special work to support ARP
- Overloaded ARP
- If your device wants to use a common hardware header without running ARP, you need to overload the default Dev->hard_header function
- Non-Ethernet Header
- In addition to the destination address, the hardware header contains some other information, the most important of which is the communication protocol
- Drivers/net/appletalk/cops.c
- Drivers/net/irda/smc_ircc.c
- Drivers/net/pp_generic.c
- Custom IOCTL commands
- When an IOCTL system call is used for a socket, the command number is a symbol defined in <linux/sockios.h>
- function Sock_ioctl directly invokes a protocol-related function
- Any IOCTL commands that are not recognized by the protocol layer are passed to the device layer
- These device-related IOCTL commands accept the third parameter from user space, a struct ifreq * pointer
- Statistics
- The last function required by the driver is Get_stats, which returns a pointer to the device statistics structure
- struct net_device_stats
- unsigned l Ong Rx_packets;
- unsigned long tx_packets;
- unsigned long rx_bytes;
- unsigned long tx_bytes;
- unsigned long rx_errors;
- unsigned long tx_errors;
- unsigned long rx_dropped;
- unsigned long tx_dropped;
- unsigned long collisions;
- unsigned long multicast;
- Multicast
- for Ethernet, the lowest bit of the multicast address at the first octet of the destination address is set to 1, and all the device cards have the corresponding bits of their hardware address cleared 0
- kernel to track multicast addresses at any given time
- driver implementation A method of multicast inventory that relies on the way the underlying hardware works in a program
- typically, when multicast is considered, hardware can be divided into three classes
- interfaces that do not handle multicast
- interface for packet multicast packets and other packets
- interfaces capable of hardware detection for multicast addresses
- kernel support for multicast
- support for multicast packets consists of a device function, a data structure, and several device flags
- Void (*dev_set_multicast_list) (struct NE T_device *dev);
- struct dev_mc_list *dev->mc_list;
- int dev->mc_count;
- <linux/netdevice.h>
- struct dev_mc_list
- struct dev_mc_list *next
- __u8 Dmi_addr[max_addr_len];
- unsigned char dmi_addrlen;
- int dmi_users;
- int dmi_gusers;
- Other knowledge points
- Support for media-independent interfaces
- The Media-independent interface (Media independent Interface, MII) is a IEEE802.3 standard that describes how an Ethernet transceiver is connected to a network controller
- <linux/mii.h>
- Int (*mdio_read) (struct net_device *dev, int phy_id, int location);
- void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
- Drivers/net/mii.c
- Ethtool Support
- Ethtool is a tool for system administrators to control network interfaces
- Use Ethtool to control many interface parameters including speed, media type, duplex operation, DMA settings, hardware verification, wake on LAN operation only when the driver supports Ethtool
- http://sf.net/projects/gkernel/
- <linux/ethtool.h>
- struct ETHTOOL_OPS
- Netpoll
- It appears to allow the kernel to send and receive packets when the network and I/O subsystem are not yet fully available
- For network console and remote kernel debugging
- Implementing the Netpoll driver requires implementing the Poll_controller function to respond to the controller in the absence of a device interrupt
"Linux Device Drivers" The 17th Chapter Network Driver--note