Linux2.6 kernel protocol stack series-TCP protocol 1. Send, linux2.6 -- tcp

Source: Internet
Author: User

Linux2.6 kernel protocol stack series-TCP protocol 1. Send, linux2.6 -- tcp

Before introducing the tcp sending function, we must first introduce a key structure sk_buff. in linux, The sk_buff structure represents a packet:

See the sending function source code. Here we do not focus on the scattered hardware-aggregation:

/* Sendmsg System Call implementation at the TCP layer */int tcp_sendmsg (struct kiocb * iocb, struct sock * sk, struct msghdr * msg, size_t size) {struct iovec * iov; struct tcp_sock * tp = tcp_sk (sk); struct sk_buff * skb;/* One packet */int iovlen, flags; int mss_now; int err, copied; long timeo; /* obtain the lock of the Set interface */lock_sock (sk); TCP_CHECK_TIMER (sk);/* calculate the blocking timeout time based on the mark */flags = msg-> msg_flags; timeo = sock_sndtimeo (sk, flags & MSG_DONTWAIT);/* Wait for a conne Ction to finish. */if (1 <sk-> sk_state )&~ (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)/* only the two statuses can send messages */if (err = sk_stream_wait_connect (sk, & timeo ))! = 0)/* Wait for the connection to be correctly established in other states, and handle errors when the connection times out */goto out_err;/* This shoshould be in poll */clear_bit (SOCK_ASYNC_NOSPACE, & sk-> sk_socket-> flags);/* obtain valid MSS. If OOB is supported, TSO is not supported, MSS should be a relatively small value */mss_now = tcp_current_mss (sk ,! (Flags & MSG_OOB);/* OK commence sending. * // * obtain the pointer to the buffer to be sent array and its length */iovlen = msg-> msg_iovlen; iov = msg-> msg_iov; /* copied indicates the number of bytes that are copied from the user data block to skb. */Copied = 0; err =-EPIPE;/* If an interface set has an error, data cannot be sent, returned EPIPE Error */if (sk-> sk_err | (sk-> sk_shutdown & SEND_SHUTDOWN) goto do_error; while (-- iovlen> = 0) {/* process all data blocks to be sent * // * pointer and length of the buffer to be segmented */int seglen = iov-> iov_len; unsigned char _ user * from = iov-> iov_base; iov ++; while (seglen> 0) {/* process all data in a single data block */int copy; /* Get the last sk_buff pointer of the transmission queue. The following section is used to check whether the transmission queue has a full segment and the current segment length is less than 1 MSS. A new data segment */skb = sk-> sk_write_queue.prev;/* the queue is a two-way linked list, access the last segment of the socket through the prev of the queue header. First, check whether there are data segments in the transmission queue header. If the value is NULL, you do not need to check whether the data segment is not full. */If (! Sk-> sk_send_head |/* The sending queue is empty, and the obtained skb is invalid * // * If skb is valid, but it does not have any extra space to copy new data */(copy = mss_now-skb-> len) <= 0) {/* Create a new segment for user data */new_segment:/* The Data Length in the sending queue reaches the upper limit of the sending buffer, waiting for the buffer */if (! Sk_stream_memory_free (sk) goto wait_for_sndbuf;/* if there is enough memory, allocate a new buffer for TCP data segments. If the hardware supports the distributed-clustering technology, a data page size buffer is allocated. Otherwise, a buffer with a size of 1 MSs will be allocated. */Skb = sk_stream_alloc_pskb (sk, select_size (sk, tp), 0, sk-> sk_allocation);/* An error occurred while allocating a new skb, indicates that the system memory is insufficient. Wait for the memory to be released */if (! Skb) goto wait_for_memory;/* determines whether the hardware performs the checksum based on the characteristics of the routing network device */if (sk-> sk_route_caps & (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | bytes )) skb-> ip_summed = CHECKSUM_HW; skb_entail (sk, tp, skb);/* Add the new SKB segment to the end of the sending queue */copy = mss_now; /* The data size to be copied this time is MSS */}/* The data length to be copied copy cannot be greater than the remaining length of the current segment, and the seglen Subtraction is below. */If (copy> seglen) copy = seglen;/* there is space at the bottom of the skb linear storage area */if (skb_tailroom (skb)> 0) {/* only copy the data size of the remaining space at the bottom of the skb bucket */if (copy> skb_tailroom (skb) copy = skb_tailroom (skb ); /* copy Data of the specified length from the user space to skb. if the data fails, exit */if (err = skb_add_data (skb, from, copy ))! = 0) goto do_fault;}/* There is no space at the bottom of the linear storage area. Copy it to the distributed/clustered storage area */else {... // ignore} if (! Copied)/* if no data is copied, cancel the PSH flag */TCP_SKB_CB (skb)-> flags & = ~ TCPCB_FLAG_PSH;/* update the sequence number of the last packet in the sending queue */tp-> write_seq + = copy;/* update the ending sequence number of the current data segment skb, to include all sequences covered by the current segment. */TCP_SKB_CB (skb)-> end_seq + = copy; skb_shinfo (skb)-> tso_segs = 0;/* update the data replication pointer, point it to the start position of the data to be copied, and then update the number of bytes to be copied. */From + = copy; copied + = copy;/* if all the data has been copied, exit. tcp_push () is called to send the data in the transmission queue in segments. */If (seglen-= copy) = 0 & iovlen = 0) goto out;/* It indicates that all user buffers have not been copied to the socket buffer, check that if the data in the current skb is smaller than the mss, you can continue to copy the data. Or if OOB data is sent, the sending process is skipped and the data is copied */if (skb-> len! = Mss_now | (flags & MSG_OOB) continue;/* indicates that the current data segment is full. Call foced_push () to check whether the force push flag is set for the last segment in the transmission queue. If the force push flag is set, the receiver application needs to process the data first. Data must be sent immediately, that is, the data generated after the last sending has exceeded half of the value in the notification window */if (forced_push (tp )) {/* send data after setting the PSH flag */tcp_mark_push (tp, skb ); /* call this function based on the Nagle algorithm, congestion window, and sending window to start the transmission of segments to be sent. */_ Tcp_push_pending_frames (sk, tp, mss_now, TCP_NAGLE_PUSH);}/* although data is not required, only the current segment exists in the sending queue, also send it out * // * If the data cannot be forcibly pushed and there is only one data segment in the transmission queue, call tcp_push_one () to push the data segment to the transmission queue. */Else if (skb = sk-> sk_send_head) tcp_push_one (sk, mss_now);/* Then segment the remaining data in the internal loop iteration. */Continue; wait_for_sndbuf:/* wait because the sending queue is full */set_bit (SOCK_NOSPACE, & sk-> sk_socket-> flags); wait_for_memory: if (copied) /* although there is no memory, this call copies the data to the buffer zone and calls tcp_push to send it out */tcp_push (sk, tp, flags &~ MSG_MORE, mss_now, TCP_NAGLE_PUSH);/* Waiting For memory availability */if (err = sk_stream_wait_memory (sk, & timeo ))! = 0) goto do_error;/* if no memory exists, the system returns a failure upon timeout * // * after sleep, the MSS may change, recalculate */mss_now = tcp_current_mss (sk ,! (Flags & MSG_OOB) ;}} out: if (copied)/* Copies data from the user State and sends it */tcp_push (sk, tp, flags, mss_now, tp-> nonagle); TCP_CHECK_TIMER (sk); release_sock (sk);/* returns */return copied; do_fault: if (! Skb-> len) {/* failed to copy data. if the skb length is 0, it indicates it is newly allocated. Release it */if (sk-> sk_send_head = skb) /* If skb is the sending queue header, clear the queue header */sk-> sk_send_head = NULL ;__ skb_unlink (skb, skb-> list); sk_stream_free_skb (sk, skb ); /* release skb */} do_error: if (copied) goto out; out_err: err = sk_stream_error (sk, flags, err); TCP_CHECK_TIMER (sk); release_sock (sk ); return err ;}

For more information, see annotations.

Note the following steps:

1. TCP sends data in units of 1 MSS. The maximum segment size is calculated based on MTU. MTU is a link layer feature parameter and can be obtained from tcp_current_mss.

2. sk_stream_alloc_pskb () allocates a new buffer for TCP data. Its minimum length is 1 MSS.

3. skb_entail () sends messages to the transmission cache queue and calculates the allocated buffer memory.

4. tcp_push_one () is responsible for transmitting a data segment in the write queue. _ Tcp_push_pending_frames () is used to transmit multiple data segments queued in the write queue.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.