http://blog.csdn.net/wswifth/article/details/5102242
I. Preface
Linux source code, the implementation of the network interface is very well worth reading, through the reading source, not only the network protocol will have a deeper understanding, but also help in the network programming, the application function has a more accurate understanding and grasp.
This paper focuses on the overall structure of the network interface program, hoping to be read as a source of some guiding text.
This article takes the Linux2.4.16 kernel as the explanation object, the kernel source code may download on the http://www.kernel.org. I read the source reference is http://lxr.linux.no/this intersection reference site, I personally think is a good tool, if there are conditions best on this site.
Two. Structure of the Network interface program
The network interface of Linux is divided into four parts: Network device interface part, network interface core part, network protocol family part, and network interface socket layer.
The Network Device Interface section is responsible for receiving and transmitting data from physical media. The implemented files are under the Linu/driver/net directory.
The core part of the network interface is the key part of the whole network interface, which provides a unified transmitting interface for the network protocol, shielding various physical media, and is responsible for distributing the packets from the lower layer to the appropriate protocols. It is the backbone part of the network interface. Its main implementation file is in the Linux/net/core directory, where LINUX/NET/CORE/DEV.C is the primary management file.
The network protocol family part is the realization of various specific protocols. Linux support Tcp/ip,ipx,x.25,appletalk and other protocols, various specific protocol implementation of the source code in the linux/net/directory of the corresponding name. Here the main discussion of TCP/IP (IPV4) protocol, the implementation of the source code in Linux/net/ipv4, where linux/net/ipv4/af_inet.c is the main management files.
The network interface Socket layer provides the user with a programming interface for the Network service. The main source code in the LINUX/NET/SOCKET.C
Three. Network Device Interface part
There are many different types of network interface devices on the physical layer, and the identifiers of the various physical devices that ARP can handle are defined in 28 lines of the file include/linux/if_arp.h. The network device interface is responsible for the control of specific physical media, receiving and transmitting data from physical media, and making various settings such as maximum data packets for physical media. Here we take the relatively simple 3com3c501 NIC driver as an example, about how this layer works. Source code in LINUX/DRIVERS/NET/3C501.C.
We consider from the intuition, a network card is of course the most important thing is to complete the reception and delivery of data, here we look at the reception and send the process is how.
Send relatively simple, in linux/drivers/net/3c501.c line 475 start el_start_xmit () This function is actually send data to 3com3c501 Ethernet card function, the specific send job is to read and write to some registers , the source of the comments are very clear, we can look at.
The work received is relatively complex. Usually, a new package comes in, or a packet is sent, and an interrupt is generated. LINUX/DRIVERS/NET/3C501.C 572 starts the function of El_interrupt (), the first half of the processing is the packet sent after the report, the latter part of the processing is a new package, that is, the receipt of new data. The El_interrupt () function does not handle the new package too much and gives the receive handler function el_receive (). El_receive () first checks if the received package is correct, and if it is a "good" packet, a buffer structure (DEV_ALLOC_SKB ()) is allocated for the package, so that the driver receives the package is completed, by calling the upper-level function Netif_rx () (Net/core /dev.c1214), hand over the bag to the top.
Now that the driver has the ability to send and receive data, how does the driver connect to the top? That is, how to send the driver to the upper layer after receiving the package, and how can the upper layer call the drivers function?
The bottom-up relationship is implemented by a driver called the upper-Netif_rx () (net/core/dev.c 1214 line) function, where the driver passes the data to the upper layer, noting that all the NIC drivers need to call this function, This is a bridge between the network interface core layer and the network interface device.
The relationship between the top and bottom is more complex. The core layer of the network interface needs to know how many network devices are available, the entry address of each device's function, and so on. The core layer of the network interface will shout, "Hey, how many devices can help me send a packet?" You can send me a line! ”。 This team starts with dev_base, and the pointer structnet_device *dev_base (linux/include/linux/netdevice.h 436) is the storage of all the devices known to the core of the network interface. For the core layer of the network interface, all the devices are a net_device structure, which is defined in Include/linux/netdevice.h,line 233, which is an abstract device seen from the point of view of the core layer of the network interface. Let's take a look at the core layer of the network interface to see the features of the network device:
struct Net_device {
.........
Open ()
Stop ()
Hard_start_xmit ()
Hard_header ()
Rebuild_header ()
Set_mac_address ()
Do_ioctl ()
Set_config ()
Hard_header_cache ()
Header_cache_update ()
CHANGE_MTU ()
Tx_timeout ()
Hard_header_parse ()
Neigh_setup ()
Accept_fastpath ()
.........
}
If the core layer of the network interface needs to send data from the lower level, after dev_base find the device, the function of Dev->hard_start_xmit () is directly tuned to let the lower layer send packets.
The driver wants to let the network interface core layer know its existence, of course, to join Dev_base point to the pointer chain, and then put their own functions and various parameters and the corresponding fields in the net_device corresponding. Join Dev_base Pointer to the chain of pointers through function Register_netdev (&DEV_3C50) (linux/drivers/net/net_init.c, line 532)
Established. and the establishment of the corresponding domain and various parameters of the function in the Net_device is carried out in EL1_PROBE1 () (linux/drivers/net/3c501.c):
El1_probe1 () {
.........
Dev->open = &el_open;
Dev->hard_start_xmit = &el_start_xmit;
Dev->tx_timeout = &el_timeout;
Dev->watchdog_timeo = HZ;
Dev->stop = &el1_close;
Dev->get_stats = &el1_get_stats;
Dev->set_multicast_list = &set_multicast_list;
.........
Ether_setup (Dev);
.........
}
Further correspondence is done in Ether_setup (Dev) (drivers/net/net_init.c, line 405). We notice that the Dev->hard_start_xmit =&el_start_xmit, so that the relationship of the sending function is established, the upper layer only knows to call Dev->hard_start_xmit to send the data, The above statement tells the driver the actual send function to the upper layer.
Four. Core part of the network interface
Just talked about how the driver interfaces with the core layer of the network interface. The network interface core layer knows that the driver and the driver's function's entry is through the *dev_base pointing to the device chain, while the lower layer is called by the function Netif_rx () (net/core/dev.c
1214 rows) Pass the data to this layer.
The upper layer of the network interface core is the specific network protocol, the lower level is the driver, and we solve the underlying relationship, but the relationship with the upper layers is not resolved. First of all, discuss the network interface core layer and network protocol family part of the relationship, this relationship is also the reception and transmission of the relationship.
Network protocols, such as the IP,ARP protocol, send packets to this layer when the packet is sent, what function does this pass through? The core layer of the network interface provides a unified send interface through the Dev_queue_xmit () (net/core/dev.c,line975) function, which means that the data to be sent is passed to this layer by this function, either IP or ARP protocol. This function is called when you want to send the data. The work done by Dev_queue_xmit () will eventually be implemented to Dev->hard_start_xmit (), and Dev->hard_start_xmit () will invoke the actual driver to complete the sent task. For example, in the example above, calling Dev->hard_start_xmit () is actually called El_start_xmit ().
Now we discuss the receiving situation. The function Netif_rx () (net/core/dev.c 1214 lines) passed by the core layer of the network interface receives the data sent from the upper layers, which of course sends the packets to the top. All protocol families need to receive data, TCP/IP protocol and ARP protocol, spx/ipx IPX protocol, AppleTalk DDP and AARP protocol, etc. all need to receive data directly from the core layer of the network interface. How does the core layer of the network interface receive data to send packets to these protocols? At this time the situation and the relationship between the lower layer is very similar, the network interface core layers may have a lot of drivers for the network card, in order to know how to send data to these drivers, the front as well as outdated, is through the *dev_base this pointer to the chain to solve, now resolve and the upper layer of the relationship is through the static struct PACKET_PTYPE_BASE[16] (net/core/dev.c line 164) This array is resolved. This array contains the protocols that need to receive packets, as well as the entry of their receive functions.
As can be seen from the above, the IP protocol receives data through the IP_RCV () function, and the ARP protocol is through the ARP_RCV (), the network interface core layer as long as through this array can pass the data to the upper function.
If there is a protocol that wants to add itself to this array, it is through the Dev_add_pack () (NET/CORE/DEV.C, line233) function, which is removed from the array by the Dev_remove_pack () function. The IP layer is registered as void __init ip_init (void) in the initialization function (NET/IPV4/IP_OUTPUT.C, line 1003)
{
.........
Dev_add_pack (&ip_packet_type);
.........
}
Back to our discussion about reception, the function Netif_rx () (net/core/dev.c 1214 rows) of the network interface core layer receives the data sent from the top and see what this function does.
As it is still in the interrupted service, all is not able to handle too much, and the rest passes through CPU_RAISE_SOFTIRQ (THIS_CPU, NET_RX_SOFTIRQ).
Handing over soft interrupt handling, from OPEN_SOFTIRQ (NET_RX_SOFTIRQ, net_rx_action, NULL) can be known that the processing function of the NET_RX_SOFTIRQ soft interrupt is net_rx_action () (net/core/ DEV.C, line 1419), Net_rx_action () finds the corresponding protocol in the array ptype_base[16] based on the protocol type of the packet, and knows the processing function of the received, then gives the packet to the processing function, which is given to the upper processing, The actual invocation of the handler function is through Net_rx_action () in the Pt_prev->func () sentence. For example, if the packet is an IP protocol, Ptype_base[eth_p_ip]->func () (IP_RCV ()), the packet is given to the IP protocol.
Five. Network Protocol section
The protocol layer is really implemented in this layer. In Linux/include/linux/socket.h, the BSD of Linux
The socket defines up to 32 supported protocol families, where Pf_inet is the most familiar TCP/IP protocol family (IPV4, which does not specifically refer to IPv4). Take this protocol family as an example to see how this layer works. Implement the main file of the TCP/IP protocol family under the inux/net/ipv4/directory, LINUX/NET/IPV4/AF_INET.C is the primary administrative file.
In the Linux2.4.16, the realization of the TCP/IP protocol family inside the IGMP,TCP,UDP,ICMP,ARP,IP. Let's discuss the relationship between these protocols first. IP and ARP protocols are protocols that need to deal directly with network device interfaces, that is, from the Network Core module (CORE)
To receive data and send data. Other protocol tcp,udp,igmp,icmp need to take advantage of the IP protocol directly, need to receive data from IP protocol, and use IP protocol to send data, but also to the upper socket layer to provide a direct calling interface. You can see that the IP layer is a core protocol that needs to deal with the lower layers, and also provides the service to the upper layer so that the transmission and reception.
Let's take a look at the IP protocol layer. If the network core module (CORE) receives the data from the IP layer, the IP_PACKET_TYPE->IP_RCV () function of the IP protocol that points to the IP layer of the PTYPE_BASE[ETH_P_IP] array passes the packet to the IP layer, This means that the IP layer receives data through this function IP_RCV () (LINUX/NET/IPV4/IP_INPUT.C). IP_RCV () This function only makes some checksum checks on the IP data, and if the package is correct, the packet is given to the next handler Ip_rcv_finish () (note that the call is implemented by the Nf_hook macro). Now, the Ip_rcv_finish () function is really going to do some work on the IP layer. The main task of the IP layer is to route and decide where to send the packets. The work of routing is implemented through the function Ip_route_input () (/linux/net/ipv4/route.c,line 1622). There are these possible routes for incoming packets:
Data that belongs to the local (that is, it needs to be passed to TCP,UDP,IGMP these upper layer protocols);
A packet that needs to be forwarded (a gateway or a NAT server, etc.);
Packets that cannot be routed (incorrect address information);
What we care about now is what to do if the data is local data. Ip_route_input () calls Ip_route_input_slow () (net/ipv4/route.c, line 1312), 1559 lines in Ip_route_input_slow () rth-> u.dst.input=
Ip_local_deliver, this is the judgment that the IP packet is local to the packet and returns the address of the local packet handler function. OK, the routing work is done, return to Ip_rcv_finish (). Ip_rcv_finish () finally calls pull Skb->dst->input (SKB), from the above can be seen, this is actually called the Ip_local_deliver () function, and ip_local_deliver (), The Ip_local_deliver_finish () is then called. Now it's time to pass the packet to the top.
The situation is very similar to the Network Core module layer (CORE) passing packets to the upper layers, how to choose the right protocol from multiple protocols, and pass the data to this protocol? The Network core module layer (CORE) uses an array of ptype_base[16] to save all registered protocols that can receive data, and the same network protocol layer defines an array struct net_protocol*inet_protos[max_inet _protos] (/linux/net/ipv4/protocol.c#l102), which holds the address of all receive handler functions that require the upper layer Protocol (IGMP,TCP,UDP,ICMP) to receive data from the IP protocol layer. Let's take a look at what the TCP protocol's data structure looks like:
LINUX/NET/IPV4/PROTOCOL.C line67
static struct Inet_protocol Tcp_protocol = {
handler:tcp_v4_rcv,//functions to receive data
err_handler:tcp_v4_err,//function for error handling
Next:ipproto_previous,
PROTOCOL:IPPROTO_TCP,
Name: "TCP"
};
The first is what we care about the most, the IP layer can pass the packet to the TCP layer through this function. In the upper part of the LINUX/NET/IPV4/PROTOCOL.C, we can see that the processing function of the other protocol layers is IGMP_RCV (),
UDP_RCV (), ICMP_RCV (). Also in LINUX/NET/IPV4/PROTOCOL.C, the add protocol to the array Inet_protos[max_inet_protos] is implemented through the function Inet_add_protocol (), and the delete protocol is through INET_DEL_ Implemented by protocol (). Inet_protos[max_inet_protos] Initializes the procedure inside the linux/net/ipv4/af_inet.c inet_init () initialization function.
Inet_init () {
......
PRINTK (Kern_info "IP protocols:");
for (p = inet_protocol_base; p! = NULL;) {
struct Inet_protocol *tmp = (struct Inet_protocol *) p->next;
Inet_add_protocol (P);//Add Protocol
PRINTK ("%s%s", p->name,tmp?, ":"/n ");
p = tmp;
.........
}
If you are aware of the startup information when you start Linux, or if you command DMESG under Linux, you can see the output of this program:
The IP Protocols:icmp,udp,tcp,igmp means that now the array inet_protos[] has INET_PROTOCOL data structure ICMP,UDP,TCP,IGMP four protocols, Data structures contain the processing functions that they receive.
Linux 2.4.16 defines 32 supported Bsdsocket protocols in Linux/include/linux/socket.h, Common tcp/ip,ipx/spx,x.25, and each protocol provides different services, such as tcp/ IP protocol to support the connection service through the TCP protocol, and through the UDP protocol to support the non-connected services, in the face of so many protocols, to provide users with a unified interface is necessary, this unity is through the socket.
In the BSD socket network programming mode, the use of a series of unified functions to take advantage of communication services. For example a typical use of TCP protocol communication programs is this:
Sock_descriptor = socket (af_inet,sock_stream,0);
Connect (sock_descriptor, address,);
Send (Sock_descriptor, "Hello World");
Recv (sock_descriptor,buffer,1024,0);
The first function specifies the protocol INET protocol, the TCP/IP protocol, and the use of a connection-oriented service, which corresponds to the TCP protocol, and subsequent operations are done using the socket's standard function.
From the above we can see two questions, first the socket layer needs to be based on the user-specified protocol family (above is af_inet)
Choose a protocol from the following 32 protocols to complete the requirements of the user, when the protocol family is determined, but also to map specific services to the specific protocol family, such as when the user specifies a connection-oriented service, the INET protocol family is mapped to the TCP protocol.
Selecting a user-specified protocol from multiple protocols and handing out specific arguments to the selected protocol, which is essentially the same as the problem of an upward and downward convergence of the core layer of the network, so the solution is the same, as is the case with arrays. This array is defined in linux/net/socket.c staticstruct net_proto_family *net_families[nproto]. The elements of the array have been determined, net_families[2] is the TCP/IP protocol, net_families[3]
is the X. Protocol, which corresponds to what agreement, which is defined in include/linux/socket.h. But each of the data structures net_proto_family Ops is empty, that is, the address of the specific protocol handler is not known. The processing function of the protocol and the OPS are established through the function of Sock_register () (linux/net/socket.c), such as the TCP/IP protocol that establishes the relationship:
int __init inet_init (void) (NET/IPV4/AF_INET.C)
{
(void) Sock_register (&inet_family_ops);
}
Just give the af_inet (defined in the macro is 2), you can find the net_failies[2] inside the processing function.
The mapping of the Protocol is complete, and now the mapping of the service is done. It is certainly impossible to know what protocols are available on the lower level, so this mapping is naturally done by the protocol family. In the TCP/IP protocol family, this mapping is done through a struct
List_head Inetsw[sock_max] (net/ipv4/af_inet.c)
This array is mapped and we'll look at another array before we talk about this array inetsw_array[] (net/ipv4/af_inet.c)
static struct INET_PROTOSW inetsw_array[] =
{
{
Type:sock_stream,
PROTOCOL:IPPROTO_TCP,
Prot: &tcp_prot,
OPS: &inet_stream_ops,
Capability:-1,
no_check:0,
Flags:inet_protosw_permanent,
},
{
Type:sock_dgram,
PROTOCOL:IPPROTO_UDP,
Prot: &udp_prot,
OPS: &inet_dgram_ops,
Capability:-1,
No_check:udp_csum_default,
Flags:inet_protosw_permanent,
},
{
Type:sock_raw,
PROTOCOL:IPPROTO_IP,/* Wild card */
Prot: &raw_prot,
OPS: &inet_dgram_ops,
Capability:cap_net_raw,
No_check:udp_csum_default,
Flags:inet_protosw_reuse,
}
};
We see that sock_stream maps to the TCP protocol, SOCK_DGRAM maps to the UDP protocol, and SOCK_RAW maps to the IP protocol. Now just add the three items in the Inetsw_array to the array Inetsw[sock_max], and the addition is implemented by the function INET_REGISTER_PROTOSW (). In Inet_init ()
(NET/IPV4/AF_INET.C) completed the work.
Another thing that needs to be mapped is the socket, such as accept,send (),
How is the operation function of Connect (), release (), bind () mapped? Let's take a look at the above array of TCP entries
{
Type:sock_stream,
PROTOCOL:IPPROTO_TCP,
Prot: &tcp_prot,
OPS: &inet_stream_ops,
Capability:-1,
no_check:0,
Flags:inet_protosw_permanent,
},
We see this mapping through OPS, and prot, and let's look at Tcp_prot:
struct Proto Tcp_prot = {
Name: "TCP",
Close:tcp_close,
Connect:tcp_v4_connect,
Disconnect:tcp_disconnect,
Accept:tcp_accept,
Ioctl:tcp_ioctl,
Init:tcp_v4_init_sock,
Destroy:tcp_v4_destroy_sock,
Shutdown:tcp_shutdown,
Setsockopt:tcp_setsockopt,
Getsockopt:tcp_getsockopt,
Sendmsg:tcp_sendmsg,
Recvmsg:tcp_recvmsg,
BACKLOG_RCV:TCP_V4_DO_RCV,
Hash:tcp_v4_hash,
Unhash:tcp_unhash,
Get_port:tcp_v4_get_port,
};
So the mapping has been completed, the user calls the Connect () function, in fact, is called the Tcp_v4_connect () function, according to this picture, read the origin code to a lot simpler.
Six Sockets Layer
The previous section of the socket layer to discuss most of the things to talk about, now only talk about the socket layer and user interface.
The system calls the socket (), bind (), connect (), Accept,send (), release (), etc. are implemented in the LINUX/NET/SOCKET.C, and the function that the system calls implements is the corresponding function name plus the SYS_ prefix.
Now look at what happens next when the user calls the socket () function.
The Socket (af_inet,sock_stream,0) calls Sys_socket (), Sys_socket () then calls Socket_creat (), Socket_creat () is based on the user-supplied protocol family parameters in net_ Families[] Search for the appropriate protocol family, if the protocol family is not installed, it is necessary to request the installation of the Protocol family module, and then call the Protocol family's create () function handle handles. According to the parameter Af_inet,inet_creat () is called, in Inet_creat () according to the service type in Inetsw[sock_max]
Select the appropriate protocol and assign the operation set of the protocol to the socket, which is selected according to the SOCK_STREAM,TCP protocol.
Inet_creat () {
ANSWER=INETSW [user requirements service];
Sock->ops = answer->ops;
Sk->prot = Answer->prot
}
So far, up and down are open, it is time for everyone to source code.
Linux kernel 2.4.x network interface source structure [go]