I. In the source code of Linux, the implementation part of the network interface is very worth reading. By reading source code, not only has a deeper understanding of the network protocol, but also helps the corresponding function more accurate when networking. Understanding and grasp. This article focuses on the overall structure of the network interface program, hoping to be some guiding text as a read source code. This article uses Linux2.4.16 kernel as an object of explanation, the kernel source can be downloaded on http://www.kernel.org. I read the source code. Reference is http://lxr.linux.no/ This part of this information, I personally think is a good tool, if there is conditional best. II. Network interface program structure Linux network interface is divided into four parties: network device interface part, network interface core part, network protocol part, and network interface Socket layer. The network device interface is mainly responsible for receiving and transmitting data from physical media. The implemented file is in the Linu / Driver / Net directory. The core part of the network interface is a key part of the entire network interface. It provides a unified transmission interface for the network protocol, shields a variety of physical media, and is responsible for distributing the package from the lower level. It is a central part of the network interface. Its main implementation files in the Linux / Net / Core directory, where Linux / Net / Core / dev.c is the primary management file. Part of the network protocol is part of various specific agreements. Linux supports protocols such as TCP / IP, IPX, X.25, AppleTalk, etc., and the source code implemented by various specific protocols is in the LINUX / NET / directory. The TCP / IP (IPv4) protocol is mainly discussed here, the source code implemented in Linux / Net / IPv4, where Linux / Net / IPv4 / AF_INET.C is the main management file. The Network Interface Socket layer is a programming interface for the network service provided by the user. The main source code is in Linux / Net / Socket.c. Third. There are many different types of network interface devices on the physical layer of the network device interface, and the ARP can be processed in the 28-row of file include / Linux / if_arp.h. The symbol of the physical device. The network device interface is responsible for the control of the specific physical media, receiving and transmitting data from physical media, and performs various settings such as maximum packets. Here we use a relatively simple 3COM3C501 NT card driver as an example, probably talk about this work principle. The source code is in Linux / Drivers / Net / 3C501.c. We consider intuition, one network card, is of course the most important thing to complete the data reception and send, here let's see how the process of receiving and sending is. Transfer relatively simple, the EL_START_XMIT () function started in Linux / Drivers / Net / 3C501.c is the actual function to send data to the 3COM3C501 Ethernet card, and the specific sending work is nothing more than some registers. Reading and writing, the comment for the source code is clear, you can take a look. Received work is relatively complicated. Generally, a new package is here, or a package is sent, it will generate an interrupt. Linux / drivers / net / 3c501.c 572 starts in the function of EL_Interrupt (), the first half processes the report after the package is sent, and the second half is handled by a new package, that is, it is said that it is received. New data. The EL_INTERRUPT () function does not perform too much processing for the new package, and it is handed over to the receiving processing function EL_RECEIVE ().
El_receive () first check if the received package is correct, if a "good" package will assign a buffer structure for the package (dev_alloc_skb ()), so that the driver is completed, by calling the upper layer of function Netif_RX () (NET / CORE / dev.c1214 line), give the package to the upper layer. Now the driver has the function of sending and receiving data, how is the driver to establish a connection with the upper layer? That is to say how to give the upper layer after receiving the package, and how can the upper layer call the transmit function of the driver? From the bottom-up relationship, the driver is implemented by the driver to call the upper layer of Netif_Rx () function, the driver is handed over to the upper layer through this function, please pay attention to all NIC drivers need to call this function, which is a bridge that the network interface core layer and network interface device is connected. The relationship from the top down is complex. The network interface core layer needs to know how many network devices can be used, and the entry address of each device must know. The core layer of the network interface will shout loudly. "Hey, how many devices can help me send a packet? Please send me a team!" This team started by dev_base, pointer structNet_Device * dev_base (Linux / include / Linux / NetDevice.h 436 row) All devices that have been known from the core layer of the network interface. For network interface core layers, all devices are NET_DEVICE structures, which are defined in include / Linux / NetDevice.h, Line 233, which is an abstract device that can be seen from the corner of the network interface. Let's take a look at the network device of the network interface of the network interface. The function of the network device has the function: strunt net_device {....... open () stop () hard_start_Xmit () hard_header () rebuild_Header () set_mac_address () do_ioc () set_config () hard_header_cache () HEADER_CACHE_UPDATE () CHANGE_MTU () TX_TIMEOUT () HARD_HEADER_PARS () neigh_set () Accept_fastPath () ......... When the network interface core layer needs to send data from the next layer, after DEV_BASE finds the device, tune DEV-> hard_start_xmit () Of this function to make the underlying packet. The driver should make the network interface core layer know its existence, of course, the pointer chain points to the dev_base, and then correspond to the corresponding domain of the various parameters and NET_DEVICE. The pointer chain to which DEV_BASE is pointed is to be established by the function register_netdev (& dev_3c50) (Linux / Drivers / Net / Net_init.c, line 532).
The establishment of the corresponding domain and various parameter relationships in Net_Device is conducted 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 work in Ether_SETUP (DRIVERS / NET / NET_INIT.C, LINE 405). We noticed dev-> hard_start_xmit = & el_start_xmit, which is established in this way, and the upper layer only knows that the DEV-> hard_start_xmit This is sent to send the data. The above statement tells the actual send function of the driver to the upper layer. IV. The core part of the network interface just talked about how the driver is connected to the core layer of the network interface. The network interface core layer knows that the entry of the driver and the function of the driver is the device chain directed by * dev_base, and the lower layer is passed by calling the function Netif_Rx () (NET / CORE / dev.c1214 line) by calling this layer. This layer is of. The upper layer of the core layer of the network interface is a specific network protocol. The lower layer is the driver, and we have solved the following relationship, but the relationship between the upper layer is not resolved. First discuss the relationship between the core layer and the network protocol of the network interface, this relationship is nothing more than the relationship between reception and transmission. Network protocol, such as IP, ARP, etc., will pass the packet to this layer when sending a packet, then what function occurs by this password? The network interface core layer provides a unified sending interface to the upper layer through dev_queue_xmit () (net / core / dev.c, line975), that is, whether it is IP, or the ARP protocol, passed the data to be sent to the data to be transmitted This layer can be called when you want to send data. DEV_QUEUE_XMIT () Work will eventually be implemented to dev-> hard_start_xmit (), while dev-> hard_start_xmit () calls the actual driver to complete the sent task. For example, in the above example, call dev-> hard_start_Xmit () is actually called EL_START_XMIT (). Now discuss the receipt. The function Netif_Rx () (NET / CORE / DEV.C 1214 line) received by the network interface core layer receives the data sent by the upper layer, which is of course sent to the upper floor.
All sub-protocols of all protocols need to receive data, TCP / IP IP protocols, and ARP protocols, SPX / IPX IPX protocols, AppleTalk's DDP and AARP protocols need to receive data directly from the network interface core layer. How does the layer receive data give these protocols? At this time, the relationship between the lower layer is similar, and the core layer of the network interface may have a number of network card drivers. In order to know how to send data, the front, and how to point to these driver, it is pointed to by * dev_base. The chain is resolved, and the relationship with the upper layer is now resolved by static struct packet_ptype_base [16] (net / core / dev.c line 164). This array contains protocols that need to receive packets, as well as the portal of their reception functions. As can be seen from the above, the IP protocol receiving data is via the IP_RCV () function, and the ARP protocol is through the ARP_RCV (), and the network interface core layer can give the data to the upper layer function. If there is a protocol to add yourself to this array, it is through the DEV_ADD_PACK () (NET / CORE / dev.c, line233) function, from the array deletion is through the dev_remove_pack () function. The registration of the IP layer is a void __init ip_init (void) (NET / IPv4 / IP_Output.c, line 1003) {......... dev_add_pack (& ip_packet_type); .........} Reall back to our discussion about the reception, The function Netif_Rx () (NET / CORE / DEV.C 1214 row) passed by the network interface core layer received the data sent by the upper layer and see what this function did. Since it is still in the interrupted service, all do not handle too much thing, the rest of the thing is handed over to the soft interrupt by cpu_RAISE_SOFTIRQ (THIS_CPU, NET_RX_SOFTIRQ), from Open_Softirq (NET_RX_SOFTIRQ, NET_RX_ACITION, NULL), NET_RX_SOFTIRQ soft The interrupt processing function is NET_RX_ACTION () (NET / CORE / dev.c, line 1419), net_rx_action () finds the corresponding protocol in the array ptype_base [16] according to the protocol type of the packet, and knows the received handler Then, then pay the data package to the processing function, which is handed over to the upper processing, and the actual call processing function is in the PT_PREV-> FUNC () in NET_RX_ACTION (). For example, if the packet is an IP protocol, ptype_base [eth_p_ip] -> func () (ip_rcv ()), then hand it over to the IP protocol. 5. The network protocol part of the protocol layer is truly implemented at this layer. In Linux / Include / Linux / Socket.h, Linux's BSDSocket defines the protocols supported by 32. The PF_INET is our most familiar TCP / IP protocol (IPv4, there is no special statement, IPv4). Take this protocol as an example to see how this layer works. The main file of the TCP / IP protocol is implemented in the Inux / Net / IPv4 / Directory, Linux / Net / IPv4 / AF_INET.C is the main management file. In Linux2.4.16, IGMP, TCP, UDP, ICMP, ARP, IP, IP in TCP / IP protocol are realized. Let's discuss the relationship between these agreements. The IP and ARP protocols are protocols that need to be dealt with directly and network device interfaces, that is to receive data and send data from the Network Core Module (Core).
Other protocols TCP, UDP, IGMP, ICMP are required to directly utilize IP protocols, requiring data from the IP protocol, and transmitting data using IP protocol, while providing a direct calling interface to the upper Socket layer. It can be seen that the IP layer is a core protocol, which needs to be deal from the lower level, and provide the upper layer to provide the service and receive services. Let's first look at the IP protocol layer. Network Core Module (CORE) If the data of the IP layer is received, the IP_PACKET_TYPE-> IP_RCV () function of the IP protocol in the IP layer of the PTYPE_BASE [Eth_P_ip] array is passed to the IP layer, that is, the IP layer The data is received by this function ip_rcv () (Linux / Net / IPv4 / IP_INPUT.C). The IP_RCV () This function only has some Checksum check work for IP data. If the package is correct, the package is handed over to the next processing function IP_RCV_FINISH () (note that the call is implemented by the macro of NF_HOOK). Now, IP_RCV_FINISH () This function really wants to complete some IP layers. The main job for IP layers is to route, to decide to send the data to the company. The work of the route is achieved by function IP_ROUTE_INPUT () (/ Linux / Net / IPv4 / Route.c, Line 1622). For possible routes for the incoming packages: local data (ie, it is necessary to pass to TCP, UDP, IGMP these upper protocols); need to be forwarded (gateway or NAT server); impossible route The packet (the address information is incorrect); how we are concerned now if the data is handled when the data is local data. IP_ROUTE_INPUT () call ip_route_input_slow () (NET / IPv4 / Route.c, Line 1312), 1559 lines ip_local_dst.input = ip_local_dst.input = ip_local_dset.input = ip_local_dst.input = ip_local_dst.input = ip_local_dliver, this is the local packet And return the address of the local packet processing function. Ok, the routing work is completed, returned to IP_RCV_FINISH (). IP_RCV_FINISH () final call Skb-> DST-> Input (SKB), can be seen from above, is actually calling the ip_local_deliver () function, and ip_local_deliver (), then call ip_local_deliver_finish (). Now I really arrived in the upper layer. The current situation and the network core module layer (Core) passing the packets in the upper layer is very similar, how to select the appropriate protocol from multiple protocols, and transfer data to this protocol? Network Network Core Module Layer (CORE) Saves all of the registered protocols that can receive data through a array ptype_base [16], and the same network protocol layer also defines such an array struct net_protocol * inet_protos [max_inet_protos] (/ linux / net / IPv4 / Protocol.c # l102), which saves all addresses that require reception processing functions that require the upper level protocol (IGMP, TCP, UDP, ICMP) of the IP Protocol layer.
Let's take a look at how the data structure of the TCP protocol: Linux / Net / IPv4 / Protocol.c line67 static struct inet_protocol tcp_protocol = {handler: TCP_V4_RCV, // Receive data function err_handler: TCP_V4_ERR, // error handage Next: ipproto_previous, protocol: ipproto_tcp, name: "TCP"}; first is our most concerned, the IP layer can pass the data to TCP layer through this function. In the upper part of Linux / Net / IPv4 / Protocol.c, we can see that the processing function of other protocol layers is IGMP_RCV (), UDP_RCV (), ICMP_RCV (). Also in Linux / Net / IPv4 / Protocol.c, the array inet_protos [MAX_INET_PROTOS] adding protocols is implemented by function inet_add_protocol (), and the delete protocol is implemented by inet_del_protocol (). INET_PROTOS [MAX_INET_PROTOS] The process of initialization is in 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 have the information that is noted when you start in Linux, Or on Linux command DMESG can see this program output information: IP protocols: ICMP, UDP, TCP, IGMP, in意, The INET_PROTOCOL data structure, the data structure contains the processing functions they receive data. Linux 2.4.16 defines 32 supported BSDSocket protocols in Linux / Include / Linux / Socket.h. Common TCP / IP, IPX / SPX, X.25, etc., and each agreement also provides different services. For example, the TCP / IP protocol supports the connection service through the TCP protocol, and the UDP protocol supports unconnected service, facing so many protocols, providing a unified interface to the user is necessary, this uniform is made by socket. In the BSD Socket network programming mode, use a series of unified functions to utilize communication services. For example, a typical TCP protocol communication program 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 uses the connection-oriented service, which corresponds to the TCP protocol, and the subsequent operation is based on the standard function of the Socket.
From above we can see two questions, first, the Socket layer needs to complete the user's requirements according to the user-specified protocol (the AF_INET) from the following 32 protocols, and when the protocol is determined, The specific service is mapped to the specific protocol under the protocol, for example, when the user specifies the connection-oriented service, the INET protocol will be mapped to the TCP protocol. Select the user-specified protocol from multiple protocols, and give specific projections to the selected protocol, which is the same as the problem with the network core layer and downward, so the method of solving is the same, Also or by arrays. In Linux / Net / Socket.c, this array is defined in this array statuct 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.25 protocol, and the specific protocol is defined in include / linux / socket.h. However, the OPS of each data structure NET_PROTO_FAMILY is empty, that is, the address of the specific protocol handling function is not known. The processing function and the OPS establishment of the protocol are established by socket_register () (Linux / Net / Socket.c), such as the TCP / IP protocol, this is the establishment of this relationship: int __init inet_init (void) (Net / IPv4 / AF_INET.C) {(Void) Sock_Register (& INET_FAMILY_OPS);} You can find the process function inside NET_FAILIES [2] as long as the AF_INET (2) is given. The mapping of the protocol is complete, and now you have to map the service. Of course, it is certainly impossible to know what protocol in the lower layer can correspond to a specific service, so this mapping naturally completed by the protocol. In the TCP / IP protocol, this mapping is mapped by structList_head inetsw [SOCK_MAX] (NET / IPv4 / AF_INET.C), which is mapped to another array inetsw_Array [] (NET /) before talking about this array. 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 , No_check: udp_raw, no_check: udp_csum_default, flags: inet_protosw_reuse,}}; we see, Sock_Stream is mapped to the TCP protocol, and SOCK_DGRAM is mapped to the UDP protocol, and SOCK_RAW is mapped to the IP protocol.
Now just add three INETSW_ARRAY to the array inetsw [SOCK_MAX], add the function inet_register_protosw () implementation. These work is completed in inet_init () (Net / IPv4 / AF_INET.C). There is also an operation function such as Accept, Send (), Connect (), Release (), Bind (), etc., which needs to be mapped. Let's take a look at the TCP of the array of the array {TYPROTO_TREAM, Prot: & TCP_PROT, OPS: & INET_STREAM_PROT, OPS: & INET_STREAM_PROS, CAPABILITY: -1, NO_CHECK: 0, FLAGS: INET_PROTOSW_PERMANENT,}, we see this mapping is by ops, and to map the prot, let us look at tcp_prot this one: 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 mapping have been Completed, the user calls the connect () function, in fact, call the TCP_V4_CONNECT () function, according to this picture, read the origin code is simple. The Six Socket Layers Talk about the things that the Socket layer to be discussed, now only talk about the connection of the Socket layer and the user. System call socket (), bind (), connection (), accept, send (), release (), etc. is the implementation in Linux / Net / Socket.c, the function of the system call implementation is the corresponding function name plus Sys_ 's prefix. Now look at what the user calls socket (), what happened below. SOCKET (AF_INET, SOCK_STREAM, 0) calls sys_socket (), Sys_Socket () then calls socket_creat (), Socket_creat () to find a suitable protocol in Net_Families [] based on the user-provided protocol parameters, if the protocol is not The module for installing the protocol is required to be installed, and then the handle of the CREATE () function of the protocol family is called.