Recently, we are looking at the TCP/IP BSD implementation. The first is its storage management, mainly through the structure of mbuf to manage the cache. After reading a part of the data, I think the design is very good. I split the big data into small pieces of storage, which makes it easy to write and recycle the pool. When I was writing a Streaming Media Server, I had been worried about the large memory management of the corresponding frame data. After the allocated memory, how should I recycle it? Finally, I imitated the nginx memory pool, the reference count is added before each fixed-size memory block, and the memory block is allocated. When the reference count is 0, the pool is returned. After reading the Cache Management of TCP/IP, I felt that the frame data is scattered in a fixed-size mbuf. Finally, we can recycle this fixed-size structure block in a uniform way. Let's take a look at the implementation of mbuf. I. struct
Header information of mbuf
Struct m_hdr {struct mbuf * mh_next;/* pointer to the next mbuf in the chain */struct mbuf * mh_nextpkt;/* pointer to the next chain */INT mh_len; /* length of data in mbuf (excluding the header) */char * mh_data;/* pointer to the data zone */short mh_type;/* Data Type of mbuf, for example, mt_data */short mh_flags;/* mbuf ID. For specific definitions, see */}; mbuf ID # define m_ext 0x0001/* use the cluster as the external switch */# define m_pkthdr 0x0002/* indicates that mbuf contains a group header */# define m_eor 0 x 0004/* The Group ends, generally, TCP never uses this flag for the OSI protocol, because TCP is a stream protocol and has no boundaries */St. Ruct pkthdr {int Len;/* The total length of the entire mbuf linked list containing data. The reason for maintaining a group header with a total length in the first mbuf of the linked list is, when the total length is required, you can avoid viewing mh_len in all mbuf To sum */struct IFNet * rcvif;/* pointer to the receiving interface structure of the receiving group */}; here, the shared body is used to describe the content of the shared body, which depends on the m_type type. This can be learned. Struct mbuf {struct m_hdr; Union {struct pkthdr mh_pkthdr;/* m_pkthdr Set */Union {struct m_ext mh_ext;/* m_ext Set */Char mh_databuf [mhlen];} mh_dat;} MH; char m_databuf [mlen];/*! M_pkthdr ,! M_ext */} m_dat;}; Finally, several macros are defined to simplify structure operations. You can also learn this. For example, the data structure of # define m_next m_hdr.mh_next # defiene m_dat m_dat.m_databuf mbuf is as follows: m_next is used to form a group. Use m_nextpkt to form multiple groups. 2. It is also convenient to add an IP address and UDP header to mbuf. You only need to assign an mbuf and add it to the beginning of the chain. Put the first 28 bytes of the IP address and UDP address at the bottom of the Data zone of the mbuf, so that the underlying protocol can easily add the protocol header. 3. How does the input prevent data structure corruption caused by Asynchronization? The data input is asynchronous. When the NIC driver receives an interruption, the kernel calls the device driver to process the group, in this way, mbuf shares data between two protocol layers, so the data structure may be damaged when the interruption is triggered. NET/3 Code protects shared data by adjusting the interrupt priority. Network protocol processing is soft interrupt, and the input and output of a network device are interrupted. After the network device driver program is completed, the received group is placed in the IP queue, then the departure protocol handles soft interruptions. For example, when the main IP protocol layer is used to process the input group, it checks whether there is data in the linked list: struct mbuf * m; int s; S = splimp (s); if_dequeue (& ipring, m) splx (s); If (M = 0) return; splimp increases the CPU priority to the level of the network device driver to prevent any interruption of the network device driver. Splx is the priority before recovery. Iii. dtom macro # define dtom (x) (struct mbuf *) (INT) X &~ (Msize-1) msize is the size of mbuf, Which is 128 bits in 32 bits. This macro converts a data stored in any location in mbuf to mbuf. At that time, it never understood how this macro can convert struct members into struct pointers, if the macro is offset, you can still understand it. This macro is used to reset the position of the address to obtain the starting position. Later, it was thought that mbuf is always 128-byte aligned, so that the starting position can always be obtained after the address is cleared.