preface
Network subsystem is the top priority of Linux kernel. Today, we start with the network card driver and start the exploration of the network subsystem.
hardware environment
Raspberry pie 3B + is equipped with Gigabit network card LAN7515, but it uses USB2 0 channel (the maximum theoretical speed is 480Mbps), and the official Ethernet transmission rate of 300Mbps is given.
drive
LAN7515 driver for lan78xx, the source code is relatively simple, just two files/ linux/drivers/net/usb/lan78xx.c/h, compiled to produce lan78xx Ko driver file.
Drive analysis
1. USB driver registration
static struct usb_driver lan78xx_driver = { .name = DRIVER_NAME, .id_table = products, .probe = lan78xx_probe, .disconnect = lan78xx_disconnect, .suspend = lan78xx_suspend, .resume = lan78xx_resume, .reset_resume = lan78xx_reset_resume, .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, }; module_usb_driver(lan78xx_driver);
The USB kernel of lan7815 is a USB driver, so it is a USB driver of lan7815 ko.
insmod lan78xx.ko is to register the LAN7515 network card driver on the USB bus. At this time, it will traverse the registered devices on the USB bus and judge whether there are matching devices with the match method of the bus. If so, call the probe function of the driver.
Specifically:
/Under sys/bus/usb /, there are devices and drivers directories, which are the registered devices and registered drivers on the USB bus in the current system.
It can be seen that there is no lan78xx driver in the drivers directory, and we don't know which USB device in the devices directory is LAN7515 device.
Let's install the lan78xx driver
See the implementation of lan78xx_probe() function, which also confirms our above statement (registering the driver will traverse the device, seek matching, and trigger the probe if the matching is successful).
Let's check the directory under / sys/bus/usb/drivers again
You can see that the lan78xx directory has been generated, indicating that the driver registration is successful.
2. Driver and device binding
In lan78xx_ The lan78xx_ is called in the probe () function. The bind () method formally binds the lan78xx driver to the 1-1.1.1:1.1 device. This can also be reflected in the lan78xx directory.
We can also bind and unbind manually
# ifconfig -a lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:42 errors:0 dropped:0 overruns:0 frame:0 TX packets:42 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:4478 (4.3 KiB) TX bytes:4478 (4.3 KiB) # ls bind module new_id remove_id uevent unbind # echo "1-1.1.1:1.0" > bind [37493.831496] lan78xx_probe() [37494.126379] lan78xx 1-1.1.1:1.0 (unnamed net_device) (uninitialized): No External EEPROM. Setting MAC Speed [37494.144756] libphy: lan78xx-mdiobus: probed [37494.264385] lan78xx 1-1.1.1:1.0 (unnamed net_device) (uninitialized): int urb period 64 [37494.276093] lan78xx_phy_init() # ls 1-1.1.1:1.0 module remove_id unbind bind new_id uevent # ifconfig -a eth0 Link encap:Ethernet HWaddr B8:27:EB:8A:BC:F4 BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:42 errors:0 dropped:0 overruns:0 frame:0 TX packets:42 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:4478 (4.3 KiB) TX bytes:4478 (4.3 KiB) # # # echo "1-1.1.1:1.0" > unbind # ls bind module new_id remove_id uevent unbind # ifconfig -a lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:42 errors:0 dropped:0 overruns:0 frame:0 TX packets:42 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:4478 (4.3 KiB) TX bytes:4478 (4.3 KiB) #
3. Data sending and receiving
Take PC1 data link layer sending a data packet to PC2 data link layer as an example
rx
tasklet_schedule(&dev->bh); // When USB receives data, an interrupt is generated to trigger the task lan78xx_bh() lan78xx_rx_bh() rx_submit() usb_fill_bulk_urb() // Read data from USB tasklet_schedule(&dev->bh); lan78xx_bh() rx_process() lan78xx_rx() lan78xx_skb_return() -----Drive on top-------The following is the data link layer----------------------- netif_rx() // Send to data link layer
tx
struct net_device_ops { .ndo_start_xmit = lan78xx_start_xmit, } -----Above is the data link layer-------The following is the driver----------------------- lan78xx_start_xmit() skb_queue_tail() // Insert queue tasklet_schedule(&dev->bh); // Trigger task scheduling lan78xx_bh lan78xx_bh() lan78xx_tx_bh() skb_dequeue() // Fetch data ------The above is the driving network part--------The following is the driver USB part----------- usb_fill_bulk_urb() // Fill data to USB usb_submit_urb() // USB send data
RX call tree: at present, it is a little confused. The general process is that the USB hardware is interrupted, and the driver is driven to retrieve data through Rx_ After processing with process (), netif is finally called_ RX (skb), send the data to the kernel network subsystem to further process skb.
TX call tree: the kernel network subsystem finally calls ndo_start_xmit() sends data, and the interface is finally implemented by the device driver. This example is lan78xx_start_xmit(), and finally send the data to LAN7515 network card through USB. The network card then processes its own hardware and finally sends the data to the network cable.
Print frame header
static netdev_tx_t lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net) { printk("%s()\n", __FUNCTION__); struct ethhdr *eth = eth_hdr(skb); printk(KERN_INFO "DEST:" MAC_FMT "\n", MAC_ARG(eth->h_dest)); printk(KERN_INFO "SOURCE:" MAC_FMT "\n", MAC_ARG(eth->h_source)); struct iphdr *ip_header = ip_hdr(skb); printk("daddr:%x is %d.%d.%d.%d\n", ip_header->daddr, inet_ntoa(ip_header->daddr)); printk("saddr:%x is %d.%d.%d.%d\n\n", ip_header->saddr, inet_ntoa(ip_header->saddr)); ...
[44851.676380] lan78xx_start_xmit() [44851.680906] DEST:08:00:27:38:fc:d0 [44851.685656] SOURCE:b8:27:eb:8a:bc:f4 [44851.690571] daddr:6401a8c0 is 192.168.1.100 [44851.696164] saddr:101a8c0 is 192.168.1.1
Print the TX direction and drive the destination MAC, source MAC, destination IP and source IP in the data frame sent to the network card, that is, the data frame header at ① in the above figure.
summary
Network card, network card driver and kernel network subsystem. The core of what they do is to transfer data packets, including sk_buff plays a leading role in the whole process. During the analysis of network card driven sending and receiving, we also tried to print sk_buff part of the information, as a beginning of exploration. Actually, sk_buff really plays a very important role in the network subsystem, sk_ What's more, NB buffer is more important than socket buffer? So the later research route is: driver -- > sk_buff --> socket.