Analysis of USB network card sending and receiving data

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.

Keywords: Linux network net

Added by br on Sat, 12 Feb 2022 18:26:25 +0200