TCP收到对端发送的数据后,通常不能立即交付应用进程。在应用进程取走数据之前,数据需要保存在接收缓存之中。如果应用进程取数据的速度比TCP从对端收数据的速度慢,则接收缓存中的数据会越来越多。因此在skb被放入接收缓存之前必须检查接收缓存能容纳的内存数,如果超出限制则必须丢弃skb。
10.3.1 缓存占用
tcp_rcv_established中会检查接收缓存的使用情况:
5076 int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
5077 const struct tcphdr *th, unsigned int len)
5078 {
5079 struct tcp_sock *tp = tcp_sk(sk);
...
5201 if (!eaten) {
...
5205 if ((int)skb->truesize > sk->sk_forward_alloc) //剩余空间无法容纳skb
5206 goto step5;//进入慢速路径
...
5221 /* Bulk data transfer: receiver */
5222 eaten = tcp_queue_rcv(sk, skb, tcp_header_len,
5223 &fragstolen);
...
5265 step5:
...
5275 tcp_data_queue(sk, skb);
...
tcp_queue_rcv
函数:
4244 static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen,
4245 bool *fragstolen)
4246 {
4247 int eaten;
4248 struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue);
4249
4250 __skb_pull(skb, hdrlen);
4251 eaten = (tail &&
4252 tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0;
4253 tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
4254 if (!eaten) {
4255 __skb_queue_tail(&sk->sk_receive_queue, skb);
4256 skb_set_owner_r(skb, sk);
4257 }
4258 return eaten;
4259 }
skb_set_owner_r函数:
1995 static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
1996 {
1997 skb_orphan(skb);
1998 skb->sk = sk;
1999 skb->destructor = sock_rfree;
2000 atomic_add(skb->truesize, &sk->sk_rmem_alloc);
2001 sk_mem_charge(sk, skb->truesize); //sk->sk_forward_alloc -= size
2002 }
在tcp_data_queue
函数中:
4300 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
4301 {
4302 const struct tcphdr *th = tcp_hdr(skb);
4303 struct tcp_sock *tp = tcp_sk(sk);
4304 int eaten = -1;
4305 bool fragstolen = false;
...
4344 if (eaten <= 0) {
4345 queue_and_out:
4346 if (eaten < 0 &&
4347 tcp_try_rmem_schedule(sk, skb, skb->