编程知识 cdmana.com

Analysis of data sending and receiving process of Linux network card

Generally speaking , Network card has two important functions : receive data and send data .

therefore , When the network card receives the packet , To inform Linux The kernel has data to process . in addition , The NIC driver should provide Linux The interface that the kernel sends data to .

net_device Structure is Linux Objects abstracted for adapting different types of network card devices , Different NIC drivers just need to press Linux To fill in net_device Each member variable of the structure ,Linux The kernel can recognize the network card , And work .

Next, we will analyze the implementation principle of receiving and sending packets by network card devices .

net_device structure

net_device Structure is Linux The abstraction of network card device by kernel , But for historical reasons ,net_device The definition of structure is very complicated .

However, this paper mainly analyzes the implementation of receiving and sending data of network card equipment , So I won't analyze net_device All members of the structure . The members related to sending and receiving data are listed below , as follows :

struct net_device
{
    char                name[IFNAMSIZ];  //  Device name 
    ...
    unsigned int        irq;             //  Interrupt number 
    ...
    int (*init)(struct net_device *dev); //  The device initializes the interface of the device 
    ...
    int (*open)(struct net_device *dev); //  Interface called when opening the device 
    int (*stop)(struct net_device *dev); //  Interface called when shutting down the device 

    //  Send data interface 
    int (*hard_start_xmit)(struct sk_buff *skb,struct net_device *dev);
    ...
};
  • name: Name of equipment . It is used to display the name of the device on the terminal or search for the device through the device name .
  • irq: Interrupt number . When the network card receives a packet from the network , An interrupt needs to be generated to notify Linux The kernel has packets to process , and irq Is the interrupt number registered by the NIC driver to the kernel interrupt service .
  • initopenstop: They are the initialization interface of the device , Open the interface and close the interface .
  • hard_start_xmit: When you need to send data through network card device , You can call this interface to send data .

therefore , A NIC driver must complete the following two tasks :

  • By implementing net_device Structural hard_start_xmit Method to provide the function of sending data .
  • By registering the hardware interrupt service with the kernel , To inform the kernel to process the packets received by the network card device .

in other words , The function of sending data is by net_device Structural hard_start_xmit Method provides , The function of notifying the kernel to process the received packets is provided by the hardware interrupt of the network card .

chart 1 It shows the process of receiving and sending data :

chart 1 Network card receiving and sending data process

The picture above shows NS8390 network card The process of receiving and sending data ( The red brackets indicate the receiving process , The blue brackets indicate the sending process ), You can see from the picture above ,NS8390 Network card driver Two things have been done :

  • take net_device Structural hard_start_xmit Method set to ei_start_xmit.
  • towards Linux The kernel has registered ei_interrupt Hardware interrupt service .

therefore , When the network card receives a packet , Will trigger ei_interrupt Interrupt the service to inform the kernel that there are packets to process . And when you need to send data through the network card , Will call ei_start_xmit Method to send the data out .

The process of receiving data

When the network card receives a packet from the network , Will trigger ei_interrupt Interruption of service , Let's see ei_interrupt Interrupt service implementation :

void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    struct net_device *dev = dev_id;
    long e8390_base;
    int interrupts, nr_serviced = 0;
    struct ei_device *ei_local;

    e8390_base = dev->base_addr;
    ei_local = (struct ei_device *)dev->priv;

    spin_lock(&ei_local->page_lock);
    ...
    // (1)  Read the interrupt type of the network card to perform the corresponding operation 
    while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 
            && ++nr_serviced < MAX_SERVICE)
    {
        ...
        // (2)  If the interrupt type is packet received 
        if (interrupts & (ENISR_RX + ENISR_RX_ERR)) {
            ei_receive(dev); // (3)  Read data from the network card 
        }
        ...
    }
    ...
    spin_unlock(&ei_local->page_lock);
    return;
}

The above code removes a lot of hardware related operations , Because this article is not to analyze the implementation of NIC driver .

ei_interrupt The interrupt service first reads the type of interrupt , Save to interrupts variable . Then judge whether the interrupt type is received packet , If so, call ei_receive Function to read data from the network card .

We continue to analyze ei_receive Implementation of function :

static void ei_receive(struct net_device *dev)
{
    ...
    while (++rx_pkt_count < 10) 
    {
        int pkt_len;  //  The length of the packet 
        int pkt_stat; //  The state of the packet 
        ...
        if ((pkt_stat & 0x0F) == ENRSR_RXOK) { //  If the packet state is legal 
            struct sk_buff *skb;

            skb = dev_alloc_skb(pkt_len + 2); //  Apply for a packet object 
            if (skb) {
                skb_reserve(skb, 2);
                skb->dev = dev;         //  Set the device to receive the packet 
                skb_put(skb, pkt_len);  //  Increase the length of the data 

                //  Read data from network card ( Driven by network card ),  And save the data to skb in 
                ei_block_input(dev, pkt_len, skb, current_offset+sizeof(rx_frame));

                skb->protocol = eth_type_trans(skb, dev); //  Get the protocol type from the Ethernet layer 

                netif_rx(skb); //  Send the packet to the kernel network protocol stack 
                ...
            }
        }
        ...
    }
    ...
    return;
}

ei_receive Function mainly completes the following work :

  • Apply for one sk_buff Package object , And set it dev The field is the device receiving the packet .
  • By calling ei_block_input Function to read the received data from the network card , And save it to the one you just applied for sk_buff In the packet object .ei_block_input The function is implemented by the NIC driver , Therefore, we will not make a detailed analysis here .
  • By calling eth_type_trans Function gets the network layer protocol type from the Ethernet header of the packet .
  • call netif_rx Function to send the packet to the kernel network protocol stack .

When the packet is sent to the kernel network protocol stack , The processing of packets is taken over by the kernel . Generally speaking , The kernel network protocol stack will pass through the network layer IP agreement And transport layer TCP agreement perhaps UDP agreement To process packets , After processing, the data will be submitted to the application layer process for processing .

The process of sending data

When the network protocol stack needs to send data through the network card device , Would call net_device Structural hard_start_xmit Method , And for NS8390 network card Come on ,hard_start_xmit Method will be set to ei_start_xmit function .

in other words , Use NS8390 network card When sending data , Will eventually call ei_start_xmit Function to send data out . Let's see ei_start_xmit Implementation of function :

static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    ...
    length = skb->len; //  The length of the packet 
    ...
    disable_irq_nosync(dev->irq);      //  Turn off hardware interrupt 
    spin_lock(&ei_local->page_lock);   //  Lock the device ,  Avoid multicore CPU The use of equipment 
    ...
    //  Use the sending interface driven by network card to send data out ,skb->data  For the data part of the packet 
    ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
    ...
    spin_unlock(&ei_local->page_lock); //  Unlock the device 
    enable_irq(dev->irq);              //  Turn on hardware interrupt 
    ...
    return 0;
}

After deleting hardware related operations ,ei_start_xmit The implementation of the function is very simple :

  • First, turn off the hardware interrupt of the network card , To prevent interference from hardware interrupt during transmission .
  • call ei_block_output Function to send out the data of the packet , This function is implemented by network card driver , There is no detailed analysis here .
  • Turn on the hardware interrupt of the network card , Let the NIC continue to notify the kernel .

summary

This paper mainly introduces the process of receiving and sending packets by network card equipment , The initialization process of network card device is not involved . Of course, the initialization process of NIC devices is also very important , We may continue to analyze it in later articles .

This article is from WeChat official account. - Linux The kernel thing (like_linux)

The source and reprint of the original text are detailed in the text , If there is any infringement , Please contact the yunjia_community@tencent.com Delete .

Original publication time : 2021-03-19

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[User 7686797]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/04/20210408111751325s.html

Scroll to Top