日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux重置网络协议,Linux 内核网络协议栈 ------ tcp_ack 函数处理接收到的ACK包之后 ....

發(fā)布時間:2025/3/20 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux重置网络协议,Linux 内核网络协议栈 ------ tcp_ack 函数处理接收到的ACK包之后 .... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

注意 tcp_ack 是來處理接收到的ACK的,那么到底怎么去做呢?看下面:

先還上把tcp_sock的結(jié)構(gòu)放在這里,下面一些數(shù)據(jù)的分析需要用到:

structtcp_sock?{

/*?inet_connection_sock?has?to?be?the?first?member?of?tcp_sock?*/

structinet_connection_sock?????inet_conn;

u16?????tcp_header_len;/*?Bytes?of?tcp?header?to?send??????????*///?tcp頭部長度

u16?????xmit_size_goal_segs;/*?Goal?for?segmenting?output?packets?*///?分段數(shù)據(jù)包的數(shù)量

/*

*??????Header?prediction?flags

*??????0x5?10?<

*/

__be32??pred_flags;//?頭部預(yù)置位(用于檢測頭部標(biāo)識位處理ACK和PUSH之外還有沒有其他位,從而判斷是不是可以使用快速路徑處理數(shù)據(jù))

/*

*??????RFC793?variables?by?their?proper?names.?This?means?you?can

*??????read?the?code?and?the?spec?side?by?side?(and?laugh?...)

*??????See?RFC793?and?RFC1122.?The?RFC?writes?these?in?capitals.

*/

u32?????rcv_nxt;/*?What?we?want?to?receive?next?????????*///?下一個想要收到的第一個數(shù)據(jù)的字節(jié)編號

u32?????copied_seq;/*?Head?of?yet?unread?data??????????????*///?沒還有讀出的數(shù)據(jù)的頭

u32?????rcv_wup;/*?rcv_nxt?on?last?window?update?sent???*///?rcv_nxt在最后一個窗口更新時的值

u32?????snd_nxt;/*?Next?sequence?we?send????????????????*///?下一個發(fā)送的第一個字節(jié)編號

u32?????snd_una;/*?First?byte?we?want?an?ack?for????????*///?對于發(fā)出的數(shù)據(jù),都需要對方的ACK,這里標(biāo)示當(dāng)前需要被確認(rèn)的第一個字節(jié)

u32?????snd_sml;/*?Last?byte?of?the?most?recently?transmitted?small?packet?*///?最近發(fā)送的小數(shù)據(jù)包的最后一個字節(jié)

u32?????rcv_tstamp;/*?timestamp?of?last?received?ACK?(for?keepalives)?*///?最后一次接收到ACK的時間戳

u32?????lsndtime;/*?timestamp?of?last?sent?data?packet?(for?restart?window)?*///?最后一次發(fā)送數(shù)據(jù)包時間戳

u32?????tsoffset;/*?timestamp?offset?*///?時間戳偏移

structlist_head?tsq_node;/*?anchor?in?tsq_tasklet.head?list?*///

unsignedlongtsq_flags;

//?注意下面這個ucopy:就是將用戶數(shù)據(jù)從skb中拿出來放進去,然后傳給應(yīng)用進程!!!

/*?Data?for?direct?copy?to?user?*/

struct{

structsk_buff_head?????prequeue;//?預(yù)處理隊列

structtask_struct??????*task;//?預(yù)處理進程

structiovec????????????*iov;//?用戶程序(應(yīng)用程序)接收數(shù)據(jù)的緩沖區(qū)

intmemory;//?用于預(yù)處理計數(shù)

intlen;//?預(yù)處理長度

#ifdef?CONFIG_NET_DMA

/*?members?for?async?copy?*/

structdma_chan?????????*dma_chan;

intwakeup;

structdma_pinned_list??*pinned_list;

dma_cookie_t????????????dma_cookie;

#endif

}?ucopy;

//??snd_wl1:記錄發(fā)送窗口更新時,造成窗口更新的那個數(shù)據(jù)報的第一個序號。?它主要用于在下一次判斷是否需要更新發(fā)送窗口。

u32?????snd_wl1;/*?Sequence?for?window?update???????????*///?窗口更新序列號(?每一次收到確認(rèn)之后都會改變?)

u32?????snd_wnd;/*?The?window?we?expect?to?receive??????*///?我們期望收到的窗口

u32?????max_window;/*?Maximal?window?ever?seen?from?peer???*///?從對方接收到的最大窗口

u32?????mss_cache;/*?Cached?effective?mss,?not?including?SACKS?*///?有效的MSS,SACKS不算

u32?????window_clamp;/*?Maximal?window?to?advertise??????????*///?對外公布的最大的窗口

u32?????rcv_ssthresh;/*?Current?window?clamp?????????????????*///?當(dāng)前窗口值

u16?????advmss;/*?Advertised?MSS???????????????????????*///?對外公布的MSS

u8??????unused;

u8??????nonagle?????:?4,/*?Disable?Nagle?algorithm??????????????*///?Nagle算法是否有效

thin_lto????:?1,/*?Use?linear?timeouts?for?thin?streams?*///?使用線性超時處理

thin_dupack?:?1,/*?Fast?retransmit?on?first?dupack??????*///?收到第一個重復(fù)的ACK的時候是否快速重傳

repair??????:?1,

frto????????:?1;/*?F-RTO?(RFC5682)?activated?in?CA_Loss?*/

u8??????repair_queue;

u8??????do_early_retrans:1,/*?Enable?RFC5827?early-retransmit??*///?是否可以使用之前的重傳

syn_data:1,/*?SYN?includes?data?*///?data中是否包含SYN

syn_fastopen:1,/*?SYN?includes?Fast?Open?option?*///?SYN選項

syn_data_acked:1;/*?data?in?SYN?is?acked?by?SYN-ACK?*///?SYN回復(fù)

u32?????tlp_high_seq;/*?snd_nxt?at?the?time?of?TLP?retransmit.?*///?tlp重傳時候snd_nxt的值

/*?RTT?measurement?*/

u32?????srtt;/*?smoothed?round?trip?time?<

u32?????mdev;/*?medium?deviation?????????????????????*///

u32?????mdev_max;/*?maximal?mdev?for?the?last?rtt?period?*///?最大mdev

u32?????rttvar;/*?smoothed?mdev_max????????????????????*/

u32?????rtt_seq;/*?sequence?number?to?update?rttvar?????*/

u32?????packets_out;/*?Packets?which?are?"in?flight"????????*///?已經(jīng)發(fā)出去的尚未收到確認(rèn)的包

u32?????retrans_out;/*?Retransmitted?packets?out????????????*///?重傳的包

u16?????urg_data;/*?Saved?octet?of?OOB?data?and?control?flags?*///?OOB數(shù)據(jù)和控制位

u8??????ecn_flags;/*?ECN?status?bits.?????????????????????*///?ECN狀態(tài)位

u8??????reordering;/*?Packet?reordering?metric.????????????*///?包重排度量

u32?????snd_up;/*?Urgent?pointer???????????????*///?緊急指針

u8??????keepalive_probes;/*?num?of?allowed?keep?alive?probes???*/

/*

*??????Options?received?(usually?on?last?packet,?some?only?on?SYN?packets).

*/

structtcp_options_received?rx_opt;//?tcp接收選項

/*

*??????Slow?start?and?congestion?control?(see?also?Nagle,?and?Karn?&?Partridge)

*/

u32?????snd_ssthresh;/*?Slow?start?size?threshold????????????*///?慢啟動的開始大小

u32?????snd_cwnd;/*?Sending?congestion?window????????????*///?發(fā)送阻塞窗口

u32?????snd_cwnd_cnt;/*?Linear?increase?counter??????????????*///?線性增長計數(shù)器(為了窗口的擴大)

u32?????snd_cwnd_clamp;/*?Do?not?allow?snd_cwnd?to?grow?above?this?*///?snd_cwnd值不可以超過這個門限

u32?????snd_cwnd_used;

u32?????snd_cwnd_stamp;

u32?????prior_cwnd;/*?Congestion?window?at?start?of?Recovery.?*///?在剛剛恢復(fù)時候的阻塞窗口大小

u32?????prr_delivered;/*?Number?of?newly?delivered?packets?to?//?在恢復(fù)期間接收方收到的包

*?receiver?in?Recovery.?*/

u32?????prr_out;/*?Total?number?of?pkts?sent?during?Recovery.?*///?在恢復(fù)期間發(fā)出去的包

u32?????rcv_wnd;/*?Current?receiver?window??????????????*///?當(dāng)前接收窗口

u32?????write_seq;/*?Tail(+1)?of?data?held?in?tcp?send?buffer?*///?tcp發(fā)送buf中數(shù)據(jù)的尾部

u32?????notsent_lowat;/*?TCP_NOTSENT_LOWAT?*/

u32?????pushed_seq;/*?Last?pushed?seq,?required?to?talk?to?windows?*///?push序列

u32?????lost_out;/*?Lost?packets?????????????????*///?丟失的包

u32?????sacked_out;/*?SACK'd?packets???????????????*///?SACK包

u32?????fackets_out;/*?FACK'd?packets???????????????*///?FACK包

u32?????tso_deferred;

/*?from?STCP,?retrans?queue?hinting?*/

structsk_buff*?lost_skb_hint;//?用于丟失的包

structsk_buff?*retransmit_skb_hint;//?用于重傳的包

structsk_buff_head?????out_of_order_queue;/*?Out?of?order?segments?go?here?*///?接收到的無序的包保存

/*?SACKs?data,?these?2?need?to?be?together?(see?tcp_options_write)?*/

structtcp_sack_block?duplicate_sack[1];/*?D-SACK?block?*/

structtcp_sack_block?selective_acks[4];/*?The?SACKS?themselves*/

structtcp_sack_block?recv_sack_cache[4];

structsk_buff?*highest_sack;/*?skb?just?after?the?highest

*?skb?with?SACKed?bit?set

*?(validity?guaranteed?only?if

*?sacked_out?>?0)

*/

intlost_cnt_hint;

u32?????retransmit_high;/*?L-bits?may?be?on?up?to?this?seqno?*/

u32?????lost_retrans_low;/*?Sent?seq?after?any?rxmit?(lowest)?*/

u32?????prior_ssthresh;/*?ssthresh?saved?at?recovery?start?????*/

u32?????high_seq;/*?snd_nxt?at?onset?of?congestion???????*/

u32?????retrans_stamp;/*?Timestamp?of?the?last?retransmit,

*?also?used?in?SYN-SENT?to?remember?stamp?of

*?the?first?SYN.?*/

u32?????undo_marker;/*?tracking?retrans?started?here.?*/

intundo_retrans;/*?number?of?undoable?retransmissions.?*/

u32?????total_retrans;/*?Total?retransmits?for?entire?connection?*/

u32?????urg_seq;/*?Seq?of?received?urgent?pointer?*/

unsignedintkeepalive_time;/*?time?before?keep?alive?takes?place?*/

unsignedintkeepalive_intvl;/*?time?interval?between?keep?alive?probes?*/

intlinger2;

/*?Receiver?side?RTT?estimation?*/

struct{

u32?????rtt;

u32?????seq;

u32?????time;

}?rcv_rtt_est;

/*?Receiver?queue?space?*/

struct{

intspace;

u32?????seq;

u32?????time;

}?rcvq_space;

/*?TCP-specific?MTU?probe?information.?*/

struct{

u32???????????????probe_seq_start;

u32???????????????probe_seq_end;

}?mtu_probe;

u32?????mtu_info;/*?We?received?an?ICMP_FRAG_NEEDED?/?ICMPV6_PKT_TOOBIG

*?while?socket?was?owned?by?user.

*/

#ifdef?CONFIG_TCP_MD5SIG

/*?TCP?AF-Specific?parts;?only?used?by?MD5?Signature?support?so?far?*/

conststructtcp_sock_af_ops????*af_specific;

/*?TCP?MD5?Signature?Option?information?*/

structtcp_md5sig_info??__rcu?*md5sig_info;

#endif

/*?TCP?fastopen?related?information?*/

structtcp_fastopen_request?*fastopen_req;

/*?fastopen_rsk?points?to?request_sock?that?resulted?in?this?big

*?socket.?Used?to?retransmit?SYNACKs?etc.

*/

structrequest_sock?*fastopen_rsk;

};

struct tcp_sock {

/* inet_connection_sock has to be the first member of tcp_sock */

struct inet_connection_sock inet_conn;

u16 tcp_header_len; /* Bytes of tcp header to send */ // tcp頭部長度

u16 xmit_size_goal_segs; /* Goal for segmenting output packets */// 分段數(shù)據(jù)包的數(shù)量

/*

* Header prediction flags

* 0x5?10 << 16 + snd_wnd in net byte order

*/

__be32 pred_flags; // 頭部預(yù)置位(用于檢測頭部標(biāo)識位處理ACK和PUSH之外還有沒有其他位,從而判斷是不是可以使用快速路徑處理數(shù)據(jù))

/*

* RFC793 variables by their proper names. This means you can

* read the code and the spec side by side (and laugh ...)

* See RFC793 and RFC1122. The RFC writes these in capitals.

*/

u32 rcv_nxt; /* What we want to receive next */ // 下一個想要收到的第一個數(shù)據(jù)的字節(jié)編號

u32 copied_seq; /* Head of yet unread data */ // 沒還有讀出的數(shù)據(jù)的頭

u32 rcv_wup; /* rcv_nxt on last window update sent */ // rcv_nxt在最后一個窗口更新時的值

u32 snd_nxt; /* Next sequence we send */ // 下一個發(fā)送的第一個字節(jié)編號

u32 snd_una; /* First byte we want an ack for */ // 對于發(fā)出的數(shù)據(jù),都需要對方的ACK,這里標(biāo)示當(dāng)前需要被確認(rèn)的第一個字節(jié)

u32 snd_sml; /* Last byte of the most recently transmitted small packet */ // 最近發(fā)送的小數(shù)據(jù)包的最后一個字節(jié)

u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ // 最后一次接收到ACK的時間戳

u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ // 最后一次發(fā)送數(shù)據(jù)包時間戳

u32 tsoffset; /* timestamp offset */// 時間戳偏移

struct list_head tsq_node; /* anchor in tsq_tasklet.head list */ //

unsigned long tsq_flags;

// 注意下面這個ucopy:就是將用戶數(shù)據(jù)從skb中拿出來放進去,然后傳給應(yīng)用進程!!!

/* Data for direct copy to user */

struct {

struct sk_buff_head prequeue; // 預(yù)處理隊列

struct task_struct *task; // 預(yù)處理進程

struct iovec *iov; // 用戶程序(應(yīng)用程序)接收數(shù)據(jù)的緩沖區(qū)

int memory; // 用于預(yù)處理計數(shù)

int len; // 預(yù)處理長度

#ifdef CONFIG_NET_DMA

/* members for async copy */

struct dma_chan *dma_chan;

int wakeup;

struct dma_pinned_list *pinned_list;

dma_cookie_t dma_cookie;

#endif

} ucopy;

// ?snd_wl1:記錄發(fā)送窗口更新時,造成窗口更新的那個數(shù)據(jù)報的第一個序號。 它主要用于在下一次判斷是否需要更新發(fā)送窗口。

u32 snd_wl1; /* Sequence for window update */ // 窗口更新序列號( 每一次收到確認(rèn)之后都會改變 )

u32 snd_wnd; /* The window we expect to receive */ // 我們期望收到的窗口

u32 max_window; /* Maximal window ever seen from peer */ // 從對方接收到的最大窗口

u32 mss_cache; /* Cached effective mss, not including SACKS */ // 有效的MSS,SACKS不算

u32 window_clamp; /* Maximal window to advertise */ // 對外公布的最大的窗口

u32 rcv_ssthresh; /* Current window clamp */ // 當(dāng)前窗口值

u16 advmss; /* Advertised MSS */ // 對外公布的MSS

u8 unused;

u8 nonagle : 4,/* Disable Nagle algorithm? */ // Nagle算法是否有效

thin_lto : 1,/* Use linear timeouts for thin streams */ // 使用線性超時處理

thin_dupack : 1,/* Fast retransmit on first dupack */ // 收到第一個重復(fù)的ACK的時候是否快速重傳

repair : 1,

frto : 1;/* F-RTO (RFC5682) activated in CA_Loss */

u8 repair_queue;

u8 do_early_retrans:1,/* Enable RFC5827 early-retransmit */ // 是否可以使用之前的重傳

syn_data:1, /* SYN includes data */ // data中是否包含SYN

syn_fastopen:1, /* SYN includes Fast Open option */ // SYN選項

syn_data_acked:1;/* data in SYN is acked by SYN-ACK */ // SYN回復(fù)

u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ // tlp重傳時候snd_nxt的值

/* RTT measurement */

u32 srtt; /* smoothed round trip time << 3 */ // 往返時間

u32 mdev; /* medium deviation */ //

u32 mdev_max; /* maximal mdev for the last rtt period */ // 最大mdev

u32 rttvar; /* smoothed mdev_max */

u32 rtt_seq; /* sequence number to update rttvar */

u32 packets_out; /* Packets which are "in flight" */ // 已經(jīng)發(fā)出去的尚未收到確認(rèn)的包

u32 retrans_out; /* Retransmitted packets out */ // 重傳的包

u16 urg_data; /* Saved octet of OOB data and control flags */ // OOB數(shù)據(jù)和控制位

u8 ecn_flags; /* ECN status bits. */ // ECN狀態(tài)位

u8 reordering; /* Packet reordering metric. */ // 包重排度量

u32 snd_up; /* Urgent pointer */ // 緊急指針

u8 keepalive_probes; /* num of allowed keep alive probes */

/*

* Options received (usually on last packet, some only on SYN packets).

*/

struct tcp_options_received rx_opt; // tcp接收選項

/*

* Slow start and congestion control (see also Nagle, and Karn & Partridge)

*/

u32 snd_ssthresh; /* Slow start size threshold */ // 慢啟動的開始大小

u32 snd_cwnd; /* Sending congestion window */ // 發(fā)送阻塞窗口

u32 snd_cwnd_cnt; /* Linear increase counter */ // 線性增長計數(shù)器(為了窗口的擴大)

u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ // snd_cwnd值不可以超過這個門限

u32 snd_cwnd_used;

u32 snd_cwnd_stamp;

u32 prior_cwnd; /* Congestion window at start of Recovery. */ // 在剛剛恢復(fù)時候的阻塞窗口大小

u32 prr_delivered; /* Number of newly delivered packets to // 在恢復(fù)期間接收方收到的包

* receiver in Recovery. */

u32 prr_out; /* Total number of pkts sent during Recovery. */ // 在恢復(fù)期間發(fā)出去的包

u32 rcv_wnd; /* Current receiver window */ // 當(dāng)前接收窗口

u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ // tcp發(fā)送buf中數(shù)據(jù)的尾部

u32 notsent_lowat; /* TCP_NOTSENT_LOWAT */

u32 pushed_seq; /* Last pushed seq, required to talk to windows */ // push序列

u32 lost_out; /* Lost packets */ // 丟失的包

u32 sacked_out; /* SACK'd packets */ // SACK包

u32 fackets_out; /* FACK'd packets */ // FACK包

u32 tso_deferred;

/* from STCP, retrans queue hinting */

struct sk_buff* lost_skb_hint; // 用于丟失的包

struct sk_buff *retransmit_skb_hint; // 用于重傳的包

struct sk_buff_head out_of_order_queue; /* Out of order segments go here */ // 接收到的無序的包保存

/* SACKs data, these 2 need to be together (see tcp_options_write) */

struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */

struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/

struct tcp_sack_block recv_sack_cache[4];

struct sk_buff *highest_sack; /* skb just after the highest

* skb with SACKed bit set

* (validity guaranteed only if

* sacked_out > 0)

*/

int lost_cnt_hint;

u32 retransmit_high; /* L-bits may be on up to this seqno */

u32 lost_retrans_low; /* Sent seq after any rxmit (lowest) */

u32 prior_ssthresh; /* ssthresh saved at recovery start */

u32 high_seq; /* snd_nxt at onset of congestion */

u32 retrans_stamp; /* Timestamp of the last retransmit,

* also used in SYN-SENT to remember stamp of

* the first SYN. */

u32 undo_marker; /* tracking retrans started here. */

int undo_retrans; /* number of undoable retransmissions. */

u32 total_retrans; /* Total retransmits for entire connection */

u32 urg_seq; /* Seq of received urgent pointer */

unsigned int keepalive_time; /* time before keep alive takes place */

unsigned int keepalive_intvl; /* time interval between keep alive probes */

int linger2;

/* Receiver side RTT estimation */

struct {

u32 rtt;

u32 seq;

u32 time;

} rcv_rtt_est;

/* Receiver queue space */

struct {

int space;

u32 seq;

u32 time;

} rcvq_space;

/* TCP-specific MTU probe information. */

struct {

u32 probe_seq_start;

u32 probe_seq_end;

} mtu_probe;

u32 mtu_info; /* We received an ICMP_FRAG_NEEDED / ICMPV6_PKT_TOOBIG

* while socket was owned by user.

*/

#ifdef CONFIG_TCP_MD5SIG

/* TCP AF-Specific parts; only used by MD5 Signature support so far */

const struct tcp_sock_af_ops *af_specific;

/* TCP MD5 Signature Option information */

struct tcp_md5sig_info __rcu *md5sig_info;

#endif

/* TCP fastopen related information */

struct tcp_fastopen_request *fastopen_req;

/* fastopen_rsk points to request_sock that resulted in this big

* socket. Used to retransmit SYNACKs etc.

*/

struct request_sock *fastopen_rsk;

};

關(guān)于窗口的操作值snd_una,snd_wnd等可以看下面的圖形:

先看發(fā)送窗口:

再看接收窗口:

還有tcp_skb_cb結(jié)構(gòu):

structtcp_skb_cb?{

union{

structinet_skb_parm????h4;

#if?defined(CONFIG_IPV6)?||?defined?(CONFIG_IPV6_MODULE)

structinet6_skb_parm???h6;

#endif

}?header;/*?For?incoming?frames??????*/

__u32???????seq;//?當(dāng)前tcp包的第一個序列號

__u32???????end_seq;//?表示結(jié)束的序列號:seq?+?FIN?+?SYN?+?數(shù)據(jù)長度len

__u32???????when;//?用于計算RTT

__u8????????flags;//?tcp頭的flag

__u8????????sacked;//?SACK/FACK的狀態(tài)flag或者是sack?option的偏移

__u32???????ack_seq;//?ack(確認(rèn))的序列號

};

struct tcp_skb_cb {

union {

struct inet_skb_parmh4;

#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)

struct inet6_skb_parmh6;

#endif

} header;/* For incoming frames*/

__u32seq; // 當(dāng)前tcp包的第一個序列號

__u32end_seq; // 表示結(jié)束的序列號:seq + FIN + SYN + 數(shù)據(jù)長度len

__u32when; // 用于計算RTT

__u8flags; // tcp頭的flag

__u8sacked; // SACK/FACK的狀態(tài)flag或者是sack option的偏移

__u32ack_seq; // ack(確認(rèn))的序列號

};

關(guān)于tcp頭的標(biāo)識(flags)可以取:

#define?TCPCB_FLAG_FIN??????0x01??//?FIN?結(jié)束符

#define?TCPCB_FLAG_SYN??????0x02??//?SYN?握手

#define?TCPCB_FLAG_RST??????0x04??//?RST?重置

#define?TCPCB_FLAG_PSH??????0x08??//?PSH?接收方要立即處理

#define?TCPCB_FLAG_ACK??????0x10??//?ACK?ack段有效

#define?TCPCB_FLAG_URG??????0x20??//?URG?緊急指針

#define?TCPCB_FLAG_ECE??????0x40??//?ECE?有擁塞情況(可能是傳播線路上的擁塞,例如路由器提供的信息)

#define?TCPCB_FLAG_CWR??????0x80??//?CWR?(發(fā)生某種擁塞,例如ICMP源抑制、本地設(shè)備擁塞)

#define TCPCB_FLAG_FIN0x01 // FIN 結(jié)束符

#define TCPCB_FLAG_SYN0x02 // SYN 握手

#define TCPCB_FLAG_RST0x04 // RST 重置

#define TCPCB_FLAG_PSH0x08 // PSH 接收方要立即處理

#define TCPCB_FLAG_ACK0x10 // ACK ack段有效

#define TCPCB_FLAG_URG0x20 // URG 緊急指針

#define TCPCB_FLAG_ECE0x40 // ECE 有擁塞情況(可能是傳播線路上的擁塞,例如路由器提供的信息)

#define TCPCB_FLAG_CWR0x80 // CWR (發(fā)生某種擁塞,例如ICMP源抑制、本地設(shè)備擁塞)

sack的標(biāo)識:

#define?TCPCB_SACKED_ACKED??0x01?//?tcp的cb結(jié)構(gòu)上是被sack確認(rèn)的

#define?TCPCB_SACKED_RETRANS????0x02?//?重傳幀

#define?TCPCB_LOST??????0x04?//?丟失

#define?TCPCB_TAGBITS???????0x07?//?tag?bits??

#define?TCPCB_EVER_RETRANS??0x80

#define?TCPCB_RETRANS???????(TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS)

#define TCPCB_SACKED_ACKED0x01 // tcp的cb結(jié)構(gòu)上是被sack確認(rèn)的

#define TCPCB_SACKED_RETRANS0x02 // 重傳幀

#define TCPCB_LOST0x04 // 丟失

#define TCPCB_TAGBITS0x07 // tag bits ?

#define TCPCB_EVER_RETRANS0x80

#define TCPCB_RETRANS(TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS)

OK,回到tcp_ack函數(shù),函數(shù)的主要功能是:

1 更新重傳隊列。

2 更新發(fā)送窗口。

3 從sack的信息或者重復(fù)ack來決定是否進入擁塞模式。

/*?This?routine?deals?with?incoming?acks,?but?not?outgoing?ones.?*/

staticinttcp_ack(structsock?*sk,structsk_buff?*skb,intflag)

{

structinet_connection_sock?*icsk?=?inet_csk(sk);//?獲得連接sock

structtcp_sock?*tp?=?tcp_sk(sk);//?獲得tcp_sock

u32?prior_snd_una?=?tp->snd_una;//?獲得未發(fā)送確認(rèn)的序號

u32?ack_seq?=?TCP_SKB_CB(skb)->seq;//?獲得數(shù)據(jù)序號

u32?ack?=?TCP_SKB_CB(skb)->ack_seq;//?獲得ack序號(用于確認(rèn)的序號)

u32?prior_in_flight;

u32?prior_fackets;

intprior_packets;

intfrto_cwnd?=?0;

/*?If?the?ack?is?newer?than?sent?or?older?than?previous?acks

*?then?we?can?probably?ignore?it.

*/

if(after(ack,?tp->snd_nxt))//?如果確認(rèn)序號比我還下一個準(zhǔn)備發(fā)送的序號還要大,即確認(rèn)了我們尚未發(fā)送的數(shù)據(jù),那么顯然不合理

gotouninteresting_ack;//?沒有意義的ACK

if(before(ack,?prior_snd_una))//?如果ack確認(rèn)比我期望的確認(rèn)序號小,那么可能是以前老的ack,丟棄!!!

gotoold_ack;//?老的ack

if(after(ack,?prior_snd_una))//?如果ack確認(rèn)比我期望的第一個ack要大,但是經(jīng)過上面我們還知道沒有超過我沒有發(fā)送的數(shù)據(jù)序號,范圍

flag?|=?FLAG_SND_UNA_ADVANCED;//?那么設(shè)置標(biāo)識~

if(sysctl_tcp_abc)?{//?是否設(shè)置了tcp_abc,若有則我們不需要對每個ack確認(rèn)都要擁塞避免,所以我們需要計算已經(jīng)ack(確認(rèn))的字節(jié)數(shù)。

if(icsk->icsk_ca_state?

tp->bytes_acked?+=?ack?-?prior_snd_una;//?已經(jīng)(確定)ack的字節(jié)數(shù)增大了(?ack?-?prior_snd_una?)大小

elseif(icsk->icsk_ca_state?==?TCP_CA_Loss)

/*?we?assume?just?one?segment?left?network?*/

tp->bytes_acked?+=?min(ack?-?prior_snd_una,

tp->mss_cache);

}

prior_fackets?=?tp->fackets_out;//?得到fack的數(shù)據(jù)包的字節(jié)數(shù)

prior_in_flight?=?tcp_packets_in_flight(tp);//?計算還在傳輸?shù)臄?shù)據(jù)段的字節(jié)數(shù),下面會說手這個函數(shù)!(?1?)

if(!(flag?&?FLAG_SLOWPATH)?&&?after(ack,?prior_snd_una))?{//?如果不是“慢路徑”?&&?ack確認(rèn)比其需要的第一個大(正確的確認(rèn)序號)

/*?Window?is?constant,?pure?forward?advance.

*?No?more?checks?are?required.

*?Note,?we?use?the?fact?that?SND.UNA>=SND.WL2.

*/

tcp_update_wl(tp,?ack,?ack_seq);//?需要更新sock中的snd_wl1字段:tp->snd_wl1?=?ack_seq;(?記錄造成發(fā)送窗口更新的第一個數(shù)據(jù)?)

tp->snd_una?=?ack;//?snd_una更新為已經(jīng)確認(rèn)的序列號!下一次期待從這里開始的確認(rèn)!!!

flag?|=?FLAG_WIN_UPDATE;//?窗口更新標(biāo)識

tcp_ca_event(sk,?CA_EVENT_FAST_ACK);//?重要函數(shù)!!!進入擁塞操作!這個函數(shù)最后看,這里處理的是“正常的ACK”事件(999999)

NET_INC_STATS_BH(LINUX_MIB_TCPHPACKS);

}else{

if(ack_seq?!=?TCP_SKB_CB(skb)->end_seq)//?如果不相等,那么說明還是帶有數(shù)據(jù)一起的~不僅僅是一個ACK的包

flag?|=?FLAG_DATA;//?說明還是有數(shù)據(jù)的~

else

NET_INC_STATS_BH(LINUX_MIB_TCPPUREACKS);//?否則僅僅是ACK的包

flag?|=?tcp_ack_update_window(sk,?skb,?ack,?ack_seq);//?下面需要更新發(fā)送窗口~(2)

if(TCP_SKB_CB(skb)->sacked)//?然后判斷是否有sack段,有的話,我們進入sack段的處理。

flag?|=?tcp_sacktag_write_queue(sk,?skb,?prior_snd_una);//?~~~~~處理SACK(選擇確認(rèn)),以后單獨解釋

if(TCP_ECN_rcv_ecn_echo(tp,?tcp_hdr(skb)))//?判斷是否有ecn標(biāo)記,如果有的話,設(shè)置ecn標(biāo)記。

flag?|=?FLAG_ECE;//?ECE?也是用于判斷是否阻塞情況

tcp_ca_event(sk,?CA_EVENT_SLOW_ACK);//?重要函數(shù)!!!進入擁塞操作!這個函數(shù)最后看,這里處理“其他ACK”事件(999999)

}

/*?We?passed?data?and?got?it?acked,?remove?any?soft?error

*?log.?Something?worked...

*/

sk->sk_err_soft?=?0;

tp->rcv_tstamp?=?tcp_time_stamp;

prior_packets?=?tp->packets_out;//?獲得發(fā)出去沒有收到確認(rèn)的包數(shù)量

if(!prior_packets)//?如果為0,則可能是0窗口探測包

gotono_queue;

/*?See?if?we?can?take?anything?off?of?the?retransmit?queue.?*/

flag?|=?tcp_clean_rtx_queue(sk,?prior_fackets);//?清理重傳隊列中的已經(jīng)確認(rèn)的數(shù)據(jù)段。(3)

if(tp->frto_counter)//?處理F-RTO?(4)

frto_cwnd?=?tcp_process_frto(sk,?flag);//?處理超時重傳,暫時先不多說

/*?Guarantee?sacktag?reordering?detection?against?wrap-arounds?*/

if(before(tp->frto_highmark,?tp->snd_una))

tp->frto_highmark?=?0;

if(tcp_ack_is_dubious(sk,?flag))?{//?判斷ack是否可疑,其實本質(zhì)就是判斷可不可以增大擁塞窗口,下面會有詳細(xì)解釋(5)

/*?Advance?CWND,?if?state?allows?this.?*/

if((flag?&?FLAG_DATA_ACKED)?&&?!frto_cwnd?&&//?如果是數(shù)據(jù)確認(rèn)包

tcp_may_raise_cwnd(sk,?flag))//?檢測flag以及是否需要update擁塞窗口的大小!!!(6)--->被懷疑也有可能增大窗口哦~~~

tcp_cong_avoid(sk,?ack,?prior_in_flight);//?為真則更新?lián)砣翱?擁塞避免算法(7)--->如果允許增大窗口,那么擁塞算法處理窗口

tcp_fastretrans_alert(sk,?prior_packets?-?tp->packets_out,//?這里進入擁塞狀態(tài)的處理,非常重要的函數(shù)(對于擁塞處理來說)!!!(8)

flag);//?處理完窗口變化之后,進入快速重傳處理!!!

}else{//?沒有被懷疑(說明是正常的確認(rèn)ACK)

if((flag?&?FLAG_DATA_ACKED)?&&?!frto_cwnd)

tcp_cong_avoid(sk,?ack,?prior_in_flight);//?如果沒有被懷疑,直接擁塞算法處理窗口變化

}

if((flag?&?FLAG_FORWARD_PROGRESS)?||?!(flag?&?FLAG_NOT_DUP))

dst_confirm(sk->sk_dst_cache);

return1;

no_queue:

icsk->icsk_probes_out?=?0;

/*?If?this?ack?opens?up?a?zero?window,?clear?backoff.??It?was

*?being?used?to?time?the?probes,?and?is?probably?far?higher?than

*?it?needs?to?be?for?normal?retransmission.

*/

if(tcp_send_head(sk))//?這里判斷發(fā)送緩沖區(qū)是否為空,如果不為空,則進入判斷需要重啟keepalive定時器還是關(guān)閉定時器

tcp_ack_probe(sk);//?處理定時器函數(shù)~(暫時不看)

return1;

old_ack:

if(TCP_SKB_CB(skb)->sacked)//?如果有sack標(biāo)識

tcp_sacktag_write_queue(sk,?skb,?prior_snd_una);//?進入sack段處理(暫時不看)

uninteresting_ack:

SOCK_DEBUG(sk,"Ack?%u?out?of?%u:%u\n",?ack,?tp->snd_una,?tp->snd_nxt);//?沒有意義的包~

return0;

}

/* This routine deals with incoming acks, but not outgoing ones. */

static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)

{

struct inet_connection_sock *icsk = inet_csk(sk); // 獲得連接sock

struct tcp_sock *tp = tcp_sk(sk); // 獲得tcp_sock

u32 prior_snd_una = tp->snd_una; // 獲得未發(fā)送確認(rèn)的序號

u32 ack_seq = TCP_SKB_CB(skb)->seq; // 獲得數(shù)據(jù)序號

u32 ack = TCP_SKB_CB(skb)->ack_seq; // 獲得ack序號(用于確認(rèn)的序號)

u32 prior_in_flight;

u32 prior_fackets;

int prior_packets;

int frto_cwnd = 0;

/* If the ack is newer than sent or older than previous acks

* then we can probably ignore it.

*/

if (after(ack, tp->snd_nxt)) // 如果確認(rèn)序號比我還下一個準(zhǔn)備發(fā)送的序號還要大,即確認(rèn)了我們尚未發(fā)送的數(shù)據(jù),那么顯然不合理

goto uninteresting_ack; // 沒有意義的ACK

if (before(ack, prior_snd_una)) // 如果ack確認(rèn)比我期望的確認(rèn)序號小,那么可能是以前老的ack,丟棄!!!

goto old_ack; // 老的ack

if (after(ack, prior_snd_una)) // 如果ack確認(rèn)比我期望的第一個ack要大,但是經(jīng)過上面我們還知道沒有超過我沒有發(fā)送的數(shù)據(jù)序號,范圍

flag |= FLAG_SND_UNA_ADVANCED; // 那么設(shè)置標(biāo)識~

if (sysctl_tcp_abc) { // 是否設(shè)置了tcp_abc,若有則我們不需要對每個ack確認(rèn)都要擁塞避免,所以我們需要計算已經(jīng)ack(確認(rèn))的字節(jié)數(shù)。

if (icsk->icsk_ca_state < TCP_CA_CWR)

tp->bytes_acked += ack - prior_snd_una; // 已經(jīng)(確定)ack的字節(jié)數(shù)增大了( ack - prior_snd_una )大小

else if (icsk->icsk_ca_state == TCP_CA_Loss)

/* we assume just one segment left network */

tp->bytes_acked += min(ack - prior_snd_una,

tp->mss_cache);

}

prior_fackets = tp->fackets_out; // 得到fack的數(shù)據(jù)包的字節(jié)數(shù)

prior_in_flight = tcp_packets_in_flight(tp); // 計算還在傳輸?shù)臄?shù)據(jù)段的字節(jié)數(shù),下面會說手這個函數(shù)!( 1 )

if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) { // 如果不是“慢路徑” && ack確認(rèn)比其需要的第一個大(正確的確認(rèn)序號)

/* Window is constant, pure forward advance.

* No more checks are required.

* Note, we use the fact that SND.UNA>=SND.WL2.

*/

tcp_update_wl(tp, ack, ack_seq); // 需要更新sock中的snd_wl1字段:tp->snd_wl1 = ack_seq;( 記錄造成發(fā)送窗口更新的第一個數(shù)據(jù) )

tp->snd_una = ack; // snd_una更新為已經(jīng)確認(rèn)的序列號!下一次期待從這里開始的確認(rèn)!!!

flag |= FLAG_WIN_UPDATE; // 窗口更新標(biāo)識

tcp_ca_event(sk, CA_EVENT_FAST_ACK); // 重要函數(shù)!!!進入擁塞操作!這個函數(shù)最后看,這里處理的是“正常的ACK”事件(999999)

NET_INC_STATS_BH(LINUX_MIB_TCPHPACKS);

} else {

if (ack_seq != TCP_SKB_CB(skb)->end_seq) // 如果不相等,那么說明還是帶有數(shù)據(jù)一起的~不僅僅是一個ACK的包

flag |= FLAG_DATA; // 說明還是有數(shù)據(jù)的~

else

NET_INC_STATS_BH(LINUX_MIB_TCPPUREACKS); // 否則僅僅是ACK的包

flag |= tcp_ack_update_window(sk, skb, ack, ack_seq); // 下面需要更新發(fā)送窗口~(2)

if (TCP_SKB_CB(skb)->sacked) // 然后判斷是否有sack段,有的話,我們進入sack段的處理。

flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); // ~~~~~處理SACK(選擇確認(rèn)),以后單獨解釋

if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb))) // 判斷是否有ecn標(biāo)記,如果有的話,設(shè)置ecn標(biāo)記。

flag |= FLAG_ECE; // ECE 也是用于判斷是否阻塞情況

tcp_ca_event(sk, CA_EVENT_SLOW_ACK); // 重要函數(shù)!!!進入擁塞操作!這個函數(shù)最后看,這里處理“其他ACK”事件(999999)

}

/* We passed data and got it acked, remove any soft error

* log. Something worked...

*/

sk->sk_err_soft = 0;

tp->rcv_tstamp = tcp_time_stamp;

prior_packets = tp->packets_out; // 獲得發(fā)出去沒有收到確認(rèn)的包數(shù)量

if (!prior_packets) // 如果為0,則可能是0窗口探測包

goto no_queue;

/* See if we can take anything off of the retransmit queue. */

flag |= tcp_clean_rtx_queue(sk, prior_fackets); // 清理重傳隊列中的已經(jīng)確認(rèn)的數(shù)據(jù)段。(3)

if (tp->frto_counter) // 處理F-RTO (4)

frto_cwnd = tcp_process_frto(sk, flag); // 處理超時重傳,暫時先不多說

/* Guarantee sacktag reordering detection against wrap-arounds */

if (before(tp->frto_highmark, tp->snd_una))

tp->frto_highmark = 0;

if (tcp_ack_is_dubious(sk, flag)) { // 判斷ack是否可疑,其實本質(zhì)就是判斷可不可以增大擁塞窗口,下面會有詳細(xì)解釋(5)

/* Advance CWND, if state allows this. */

if ((flag & FLAG_DATA_ACKED) && !frto_cwnd && // 如果是數(shù)據(jù)確認(rèn)包

tcp_may_raise_cwnd(sk, flag)) // 檢測flag以及是否需要update擁塞窗口的大小!!!(6)--->被懷疑也有可能增大窗口哦~~~

tcp_cong_avoid(sk, ack, prior_in_flight); // 為真則更新?lián)砣翱?擁塞避免算法(7)--->如果允許增大窗口,那么擁塞算法處理窗口

tcp_fastretrans_alert(sk, prior_packets - tp->packets_out, // 這里進入擁塞狀態(tài)的處理,非常重要的函數(shù)(對于擁塞處理來說)!!!(8)

flag); // 處理完窗口變化之后,進入快速重傳處理!!!

} else { // 沒有被懷疑(說明是正常的確認(rèn)ACK)

if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)

tcp_cong_avoid(sk, ack, prior_in_flight); // 如果沒有被懷疑,直接擁塞算法處理窗口變化

}

if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))

dst_confirm(sk->sk_dst_cache);

return 1;

no_queue:

icsk->icsk_probes_out = 0;

/* If this ack opens up a zero window, clear backoff. It was

* being used to time the probes, and is probably far higher than

* it needs to be for normal retransmission.

*/

if (tcp_send_head(sk)) // 這里判斷發(fā)送緩沖區(qū)是否為空,如果不為空,則進入判斷需要重啟keepalive定時器還是關(guān)閉定時器

tcp_ack_probe(sk); // 處理定時器函數(shù)~(暫時不看)

return 1;

old_ack:

if (TCP_SKB_CB(skb)->sacked) // 如果有sack標(biāo)識

tcp_sacktag_write_queue(sk, skb, prior_snd_una); // 進入sack段處理(暫時不看)

uninteresting_ack:

SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);// 沒有意義的包~

return 0;

}

-----------------------------------------------------------------------------------------------------------------------------------------

看看這個函數(shù):tcp_packets_in_flight,就是計算還在傳輸中的字節(jié)數(shù):

staticinlineunsignedinttcp_packets_in_flight(conststructtcp_sock?*tp)

{

returntp->packets_out?-?tcp_left_out(tp)?+?tp->retrans_out;

}

static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp)

{

return tp->packets_out - tcp_left_out(tp) + tp->retrans_out;

}

staticinlineunsignedinttcp_left_out(conststructtcp_sock?*tp)

{

returntp->sacked_out?+?tp->lost_out;

}

static inline unsigned int tcp_left_out(const struct tcp_sock *tp)

{

return tp->sacked_out + tp->lost_out;

}

我們從tcp_sock可以知道:其實就是返回 packets_out - sacked_out - lost_out + retrans_out,就是還沒有到達對方的數(shù)據(jù)段的字節(jié)數(shù)

-----------------------------------------------------------------------------------------------------------------------------------------

下面我們看一下“發(fā)送窗口”的更新tcp_ack_update_window:

staticinttcp_ack_update_window(structsock?*sk,structsk_buff?*skb,?u32?ack,

u32?ack_seq)

{

structtcp_sock?*tp?=?tcp_sk(sk);//?獲得tcp_sock

intflag?=?0;

u32?nwin?=?ntohs(tcp_hdr(skb)->window);//?獲得skb發(fā)送方的可以接收的窗口值

if(likely(!tcp_hdr(skb)->syn))//?如果不是建立連接時候,即是普通傳遞數(shù)據(jù)時候,窗口縮放

nwin?<<=?tp->rx_opt.snd_wscale;//?接收方要求對窗口進行縮放

//?下面正式更新窗口

if(tcp_may_update_window(tp,?ack,?ack_seq,?nwin))?{//?可能需要更新窗口大小,在函數(shù)tcp_may_update_window中實際處理(1)

flag?|=?FLAG_WIN_UPDATE;//?窗口更新成功

tcp_update_wl(tp,?ack,?ack_seq);//?更新snd_wl1

if(tp->snd_wnd?!=?nwin)?{//?如果發(fā)送窗口!=縮放后的新窗口(注意skb發(fā)送方的接收窗口和本tp的發(fā)送窗口應(yīng)該一致)

tp->snd_wnd?=?nwin;//?改變窗口值

/*?Note,?it?is?the?only?place,?where

*?fast?path?is?recovered?for?sending?TCP.

*/

tp->pred_flags?=?0;

tcp_fast_path_check(sk);//?檢驗是否能夠開啟“快速路徑”(2)看下面

if(nwin?>?tp->max_window)?{//?如果調(diào)整之后的窗口大于從對方接收到的最大的窗口值

tp->max_window?=?nwin;//?調(diào)整為小的

tcp_sync_mss(sk,?inet_csk(sk)->icsk_pmtu_cookie);//?改變mss_cache

}

}

}

tp->snd_una?=?ack;//?下一個第一個需要確認(rèn)就是所有當(dāng)前已經(jīng)確認(rèn)序號之后~~~~

returnflag;

}

static int tcp_ack_update_window(struct sock *sk, struct sk_buff *skb, u32 ack,

u32 ack_seq)

{

struct tcp_sock *tp = tcp_sk(sk); // 獲得tcp_sock

int flag = 0;

u32 nwin = ntohs(tcp_hdr(skb)->window); // 獲得skb發(fā)送方的可以接收的窗口值

if (likely(!tcp_hdr(skb)->syn)) // 如果不是建立連接時候,即是普通傳遞數(shù)據(jù)時候,窗口縮放

nwin <<= tp->rx_opt.snd_wscale; // 接收方要求對窗口進行縮放

// 下面正式更新窗口

if (tcp_may_update_window(tp, ack, ack_seq, nwin)) { // 可能需要更新窗口大小,在函數(shù)tcp_may_update_window中實際處理(1)

flag |= FLAG_WIN_UPDATE; // 窗口更新成功

tcp_update_wl(tp, ack, ack_seq); // 更新snd_wl1

if (tp->snd_wnd != nwin) { // 如果發(fā)送窗口!=縮放后的新窗口(注意skb發(fā)送方的接收窗口和本tp的發(fā)送窗口應(yīng)該一致)

tp->snd_wnd = nwin; // 改變窗口值

/* Note, it is the only place, where

* fast path is recovered for sending TCP.

*/

tp->pred_flags = 0;

tcp_fast_path_check(sk); // 檢驗是否能夠開啟“快速路徑”(2)看下面

if (nwin > tp->max_window) { // 如果調(diào)整之后的窗口大于從對方接收到的最大的窗口值

tp->max_window = nwin; // 調(diào)整為小的

tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie); // 改變mss_cache

}

}

}

tp->snd_una = ack; // 下一個第一個需要確認(rèn)就是所有當(dāng)前已經(jīng)確認(rèn)序號之后~~~~

return flag;

}

下面看這個函數(shù):tcp_may_update_window

/*?Check?that?window?update?is?acceptable.

*?The?function?assumes?that?snd_una<=ack<=snd_next.

*///?這個函數(shù)是檢查窗口是否可變,只要確認(rèn)ack在snd_una~下一個需要發(fā)送的數(shù)據(jù)之間,就是需要改變窗口的!

staticinlineinttcp_may_update_window(conststructtcp_sock?*tp,

constu32?ack,constu32?ack_seq,

constu32?nwin)

{

return(after(ack,?tp->snd_una)?||//?snd_una<=ack

after(ack_seq,?tp->snd_wl1)?||//?看上面的窗口圖可以知道

(ack_seq?==?tp->snd_wl1?&&?nwin?>?tp->snd_wnd));//?調(diào)整的新窗口大于原始發(fā)送窗口

}

/* Check that window update is acceptable.

* The function assumes that snd_una<=ack<=snd_next.

*/ // 這個函數(shù)是檢查窗口是否可變,只要確認(rèn)ack在snd_una~下一個需要發(fā)送的數(shù)據(jù)之間,就是需要改變窗口的!

static inline int tcp_may_update_window(const struct tcp_sock *tp,

const u32 ack, const u32 ack_seq,

const u32 nwin)

{

return (after(ack, tp->snd_una) || // snd_una<=ack

after(ack_seq, tp->snd_wl1) || // 看上面的窗口圖可以知道

(ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd)); // 調(diào)整的新窗口大于原始發(fā)送窗口

}

看一下檢測是否可以進入“快速路徑”處理函數(shù):tcp_fast_path_check

staticinlinevoidtcp_fast_path_check(structsock?*sk)

{

structtcp_sock?*tp?=?tcp_sk(sk);

if(skb_queue_empty(&tp->out_of_order_queue)?&&

tp->rcv_wnd?&&

atomic_read(&sk->sk_rmem_alloc)?sk_rcvbuf?&&

!tp->urg_data)

tcp_fast_path_on(tp);

}

static inline void tcp_fast_path_check(struct sock *sk)

{

struct tcp_sock *tp = tcp_sk(sk);

if (skb_queue_empty(&tp->out_of_order_queue) &&

tp->rcv_wnd &&

atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&

!tp->urg_data)

tcp_fast_path_on(tp);

}

能夠進入“快速路徑”處理的基本條件是:

1 :是否ofo(亂序包隊列)隊列為空,如果不為空也就是說有亂序數(shù)據(jù)不可以進入快速路徑。

2: 當(dāng)前的接收窗口是否大于0.,如果不是,不可以進入。

3 :當(dāng)前的已經(jīng)提交的數(shù)據(jù)包大小是否小于接收緩沖區(qū)的大小,能夠放的下才可以進入快速路徑。

4: 是否含有urgent 數(shù)據(jù),不含有才可以進入快速路徑。

再看看 為tp開啟快速路徑函數(shù)tcp_fast_path_on:

staticinlinevoidtcp_fast_path_on(structtcp_sock?*tp)

{

__tcp_fast_path_on(tp,?tp->snd_wnd?>>?tp->rx_opt.snd_wscale);

}

static inline void tcp_fast_path_on(struct tcp_sock *tp)

{

__tcp_fast_path_on(tp, tp->snd_wnd >> tp->rx_opt.snd_wscale);

}

staticinlinevoid__tcp_fast_path_on(structtcp_sock?*tp,?u32?snd_wnd)

{

tp->pred_flags?=?htonl((tp->tcp_header_len?<

ntohl(TCP_FLAG_ACK)?|

snd_wnd);

}

static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)

{

tp->pred_flags = htonl((tp->tcp_header_len << 26) | // 看見沒有。本質(zhì)就是設(shè)置pred_flags變量

ntohl(TCP_FLAG_ACK) |

snd_wnd);

}

其實就是就是說標(biāo)志位除了ACK和PSH外,如果其他的存在的話,就不能用快速路徑!

-----------------------------------------------------------------------------------------------------------------------------------------

下面看進入擁塞操作函數(shù)tcp_ca_event:

有必要先看看擁塞控制結(jié)構(gòu)體:

structtcp_congestion_ops?{

structlist_head????????list;

unsignedlongflags;

/*?initialize?private?data?(optional)?*/

void(*init)(structsock?*sk);//?初始化

/*?cleanup?private?data??(optional)?*/

void(*release)(structsock?*sk);//?清除數(shù)據(jù)

/*?return?slow?start?threshold?(required)?*/

u32?(*ssthresh)(structsock?*sk);//?返回慢開始門限

/*?lower?bound?for?congestion?window?(optional)?*/

u32?(*min_cwnd)(conststructsock?*sk);//?擁塞窗口最小值

/*?do?new?cwnd?calculation?(required)?*/

void(*cong_avoid)(structsock?*sk,?u32?ack,?u32?in_flight);//?計算新的擁塞窗口

/*?call?before?changing?ca_state?(optional)?*/

void(*set_state)(structsock?*sk,?u8?new_state);//?設(shè)置擁塞狀態(tài)

/*?call?when?cwnd?event?occurs?(optional)?*/

void(*cwnd_event)(structsock?*sk,enumtcp_ca_event?ev);//?擁塞事件發(fā)生時候處理

/*?new?value?of?cwnd?after?loss?(optional)?*/

u32??(*undo_cwnd)(structsock?*sk);//?丟包之后,擁塞窗口新的值

/*?hook?for?packet?ack?accounting?(optional)?*/

void(*pkts_acked)(structsock?*sk,?u32?num_acked,?s32?rtt_us);//?包的ack計數(shù)器

/*?get?info?for?inet_diag?(optional)?*/

void(*get_info)(structsock?*sk,?u32?ext,structsk_buff?*skb);//

charname[TCP_CA_NAME_MAX];

structmodule???*owner;

};

struct tcp_congestion_ops {

struct list_head list;

unsigned long flags;

/* initialize private data (optional) */

void (*init)(struct sock *sk); // 初始化

/* cleanup private data (optional) */

void (*release)(struct sock *sk); // 清除數(shù)據(jù)

/* return slow start threshold (required) */

u32 (*ssthresh)(struct sock *sk); // 返回慢開始門限

/* lower bound for congestion window (optional) */

u32 (*min_cwnd)(const struct sock *sk); // 擁塞窗口最小值

/* do new cwnd calculation (required) */

void (*cong_avoid)(struct sock *sk, u32 ack, u32 in_flight); // 計算新的擁塞窗口

/* call before changing ca_state (optional) */

void (*set_state)(struct sock *sk, u8 new_state); // 設(shè)置擁塞狀態(tài)

/* call when cwnd event occurs (optional) */

void (*cwnd_event)(struct sock *sk, enum tcp_ca_event ev); // 擁塞事件發(fā)生時候處理

/* new value of cwnd after loss (optional) */

u32 (*undo_cwnd)(struct sock *sk); // 丟包之后,擁塞窗口新的值

/* hook for packet ack accounting (optional) */

void (*pkts_acked)(struct sock *sk, u32 num_acked, s32 rtt_us); // 包的ack計數(shù)器

/* get info for inet_diag (optional) */

void (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb); //

char name[TCP_CA_NAME_MAX];

struct module *owner;

};

看一下TCP擁塞事件:

/*?Events?passed?to?congestion?control?interface?*/

enumtcp_ca_event?{

CA_EVENT_TX_START,/*?first?transmit?when?no?packets?in?flight?*/

CA_EVENT_CWND_RESTART,/*?congestion?window?restart?*/

CA_EVENT_COMPLETE_CWR,/*?end?of?congestion?recovery?*/

CA_EVENT_FRTO,/*?fast?recovery?timeout?*/

CA_EVENT_LOSS,/*?loss?timeout?*/

CA_EVENT_FAST_ACK,/*?in?sequence?ack?*/

CA_EVENT_SLOW_ACK,/*?other?ack?*/

};

/* Events passed to congestion control interface */

enum tcp_ca_event {

CA_EVENT_TX_START, /* first transmit when no packets in flight */

CA_EVENT_CWND_RESTART, /* congestion window restart */

CA_EVENT_COMPLETE_CWR, /* end of congestion recovery */

CA_EVENT_FRTO, /* fast recovery timeout */

CA_EVENT_LOSS, /* loss timeout */

CA_EVENT_FAST_ACK, /* in sequence ack */

CA_EVENT_SLOW_ACK, /* other ack */

};

staticinlinevoidtcp_ca_event(structsock?*sk,constenumtcp_ca_event?event)//?第三個參數(shù)在上面的來說分別是:CA_EVENT_SLOW_ACK和CA_EVENT_FAST_ACK

{

conststructinet_connection_sock?*icsk?=?inet_csk(sk);//?獲得連接sock

if(icsk->icsk_ca_ops->cwnd_event)//?注意這是一個函數(shù)指針:結(jié)構(gòu)體struct?tcp_congestion_ops中的!當(dāng)擁塞事件發(fā)生時候執(zhí)行

icsk->icsk_ca_ops->cwnd_event(sk,?event);//?執(zhí)行這個事件

}

static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) // 第三個參數(shù)在上面的來說分別是:CA_EVENT_SLOW_ACK和CA_EVENT_FAST_ACK

{

const struct inet_connection_sock *icsk = inet_csk(sk); // 獲得連接sock

if (icsk->icsk_ca_ops->cwnd_event) // 注意這是一個函數(shù)指針:結(jié)構(gòu)體struct tcp_congestion_ops中的!當(dāng)擁塞事件發(fā)生時候執(zhí)行

icsk->icsk_ca_ops->cwnd_event(sk, event); // 執(zhí)行這個事件

}

擁塞窗口事件初始化在這:

if(icsk->icsk_ca_ops?==?&tcp_init_congestion_ops)?{?初始化結(jié)構(gòu)體

rcu_read_lock();

list_for_each_entry_rcu(ca,?&tcp_cong_list,?list)?{

if(try_module_get(ca->owner))?{

icsk->icsk_ca_ops?=?ca;

break;

}

/*?fallback?to?next?available?*/

}

rcu_read_unlock();

}

if (icsk->icsk_ca_ops == &tcp_init_congestion_ops) { 初始化結(jié)構(gòu)體

rcu_read_lock();

list_for_each_entry_rcu(ca, &tcp_cong_list, list) {

if (try_module_get(ca->owner)) {

icsk->icsk_ca_ops = ca;

break;

}

/* fallback to next available */

}

rcu_read_unlock();

}

structtcp_congestion_ops?tcp_init_congestion_ops??=?{

.name???????????="",

.owner??????????=?THIS_MODULE,

.ssthresh???????=?tcp_reno_ssthresh,

.cong_avoid?????=?tcp_reno_cong_avoid,

.min_cwnd???????=?tcp_reno_min_cwnd,

};

struct tcp_congestion_ops tcp_init_congestion_ops = {

.name = "",

.owner = THIS_MODULE,

.ssthresh = tcp_reno_ssthresh,

.cong_avoid = tcp_reno_cong_avoid,

.min_cwnd = tcp_reno_min_cwnd,

};

這有點問題!對于這個函數(shù)沒有進行實現(xiàn)?還是我沒有找到處理賦值的地方?無語了~~~~~~~~~~~~~~~~~~~~~~~~

或許這里面初始化:下面是關(guān)于cwnd_event所有的初始化

staticstructtcp_congestion_ops?tcp_veno?=?{

.flags??????????=?TCP_CONG_RTT_STAMP,

.init???????????=?tcp_veno_init,

.ssthresh???????=?tcp_veno_ssthresh,

.cong_avoid?????=?tcp_veno_cong_avoid,

.pkts_acked?????=?tcp_veno_pkts_acked,

.set_state??????=?tcp_veno_state,

.cwnd_event?????=?tcp_veno_cwnd_event,///

.owner??????????=?THIS_MODULE,

.name???????????="veno",

};

static struct tcp_congestion_ops tcp_veno = {

.flags = TCP_CONG_RTT_STAMP,

.init = tcp_veno_init,

.ssthresh = tcp_veno_ssthresh,

.cong_avoid = tcp_veno_cong_avoid,

.pkts_acked = tcp_veno_pkts_acked,

.set_state = tcp_veno_state,

.cwnd_event = tcp_veno_cwnd_event, ///

.owner = THIS_MODULE,

.name = "veno",

};

staticstructtcp_congestion_ops?tcp_vegas?=?{

.flags??????????=?TCP_CONG_RTT_STAMP,

.init???????????=?tcp_vegas_init,

.ssthresh???????=?tcp_reno_ssthresh,

.cong_avoid?????=?tcp_vegas_cong_avoid,

.min_cwnd???????=?tcp_reno_min_cwnd,

.pkts_acked?????=?tcp_vegas_pkts_acked,

.set_state??????=?tcp_vegas_state,

.cwnd_event?????=?tcp_vegas_cwnd_event,///

.get_info???????=?tcp_vegas_get_info,

.owner??????????=?THIS_MODULE,

.name???????????="vegas",

};

static struct tcp_congestion_ops tcp_vegas = {

.flags = TCP_CONG_RTT_STAMP,

.init = tcp_vegas_init,

.ssthresh = tcp_reno_ssthresh,

.cong_avoid = tcp_vegas_cong_avoid,

.min_cwnd = tcp_reno_min_cwnd,

.pkts_acked = tcp_vegas_pkts_acked,

.set_state = tcp_vegas_state,

.cwnd_event = tcp_vegas_cwnd_event, ///

.get_info = tcp_vegas_get_info,

.owner = THIS_MODULE,

.name = "vegas",

};

staticstructtcp_congestion_ops?tcp_yeah?=?{

.flags??????????=?TCP_CONG_RTT_STAMP,

.init???????????=?tcp_yeah_init,

.ssthresh???????=?tcp_yeah_ssthresh,

.cong_avoid?????=?tcp_yeah_cong_avoid,

.min_cwnd???????=?tcp_reno_min_cwnd,

.set_state??????=?tcp_vegas_state,

.cwnd_event?????=?tcp_vegas_cwnd_event,

.get_info???????=?tcp_vegas_get_info,

.pkts_acked?????=?tcp_yeah_pkts_acked,

.owner??????????=?THIS_MODULE,

.name???????????="yeah",

};

static struct tcp_congestion_ops tcp_yeah = {

.flags = TCP_CONG_RTT_STAMP,

.init = tcp_yeah_init,

.ssthresh = tcp_yeah_ssthresh,

.cong_avoid = tcp_yeah_cong_avoid,

.min_cwnd = tcp_reno_min_cwnd,

.set_state = tcp_vegas_state,

.cwnd_event = tcp_vegas_cwnd_event,

.get_info = tcp_vegas_get_info,

.pkts_acked = tcp_yeah_pkts_acked,

.owner = THIS_MODULE,

.name = "yeah",

};

-------------------------------------------------------------------------------------------------------------------------------------------

下面清理重傳隊列中已經(jīng)確認(rèn)的數(shù)據(jù),看函數(shù)tcp_clean_rtx_queue:

---------------------------------------------------------------------------------------------------------------------------------

現(xiàn)在可以看一下tcp_ack_is_dubious函數(shù),來判斷是不是進入了擁塞狀態(tài):

先可以看一下狀態(tài)的定義:

#define?FLAG_DATA???????????????0x01?/*?Incoming?frame?contained?data.??????????*/?????//?來了一個包含數(shù)據(jù)的包

#define?FLAG_WIN_UPDATE?????????0x02?/*?Incoming?ACK?was?a?window?update.???????*/?????//?來了一個ACK用于更新窗口

#define?FLAG_DATA_ACKED?????????0x04?/*?This?ACK?acknowledged?new?data.?????????*/?????//?對于數(shù)據(jù)的確認(rèn)

#define?FLAG_RETRANS_DATA_ACKED?0x08?/*?""?""?some?of?which?was?retransmitted.??*/?????//?對于重傳數(shù)據(jù)的確認(rèn)

#define?FLAG_SYN_ACKED??????????0x10?/*?This?ACK?acknowledged?SYN.??????????????*/?????//?對于SYN的確認(rèn)

#define?FLAG_DATA_SACKED????????0x20?/*?New?SACK.???????????????????????????????*/?????//?這是對數(shù)據(jù)的一個選擇確認(rèn)

#define?FLAG_ECE????????????????0x40?/*?ECE?in?this?ACK?????????????????????????*/?????//?確認(rèn)中旅帶有ECE信息

#define?FLAG_DATA_LOST??????????0x80?/*?SACK?detected?data?lossage.?????????????*/?????//?SACK檢測到數(shù)據(jù)丟失

#define?FLAG_SLOWPATH???????????0x100?/*?Do?not?skip?RFC?checks?for?window?update.*/???//?slowpath,需要做一些檢查

#define?FLAG_ONLY_ORIG_SACKED???0x200?/*?SACKs?only?non-rexmit?sent?before?RTO?*/

#define?FLAG_SND_UNA_ADVANCED???0x400?/*?Snd_una?was?changed?(!=?FLAG_DATA_ACKED)?*/???//?snd-una改變

#define?FLAG_DSACKING_ACK???????0x800?/*?SACK?blocks?contained?D-SACK?info?*/??????????//?包含DSACK信息

#define?FLAG_NONHEAD_RETRANS_ACKED??????0x1000?/*?Non-head?rexmitted?data?was?ACKed?*/

#define?FLAG_SACK_RENEGING??????0x2000?/*?snd_una?advanced?to?a?sacked?seq?*/??????????//?snd_una移動到一個sack中的一個位置

#define?FLAG_ACKED??????????????(FLAG_DATA_ACKED|FLAG_SYN_ACKED)?????????//?表示數(shù)據(jù)確認(rèn)或者SYN確認(rèn)

#define?FLAG_NOT_DUP????????????(FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)???//?表示ACK是不重復(fù)的

#define?FLAG_CA_ALERT???????????(FLAG_DATA_SACKED|FLAG_ECE)??????????????//?表示是否在進入擁塞狀態(tài)的時候被alert(原因可能是SACK丟包或者路由器提示擁塞)

#define?FLAG_FORWARD_PROGRESS???(FLAG_ACKED|FLAG_DATA_SACKED)????????????//?選擇確認(rèn)

#define FLAG_DATA 0x01 /* Incoming frame contained data. */ // 來了一個包含數(shù)據(jù)的包

#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ // 來了一個ACK用于更新窗口

#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ // 對于數(shù)據(jù)的確認(rèn)

#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ // 對于重傳數(shù)據(jù)的確認(rèn)

#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ // 對于SYN的確認(rèn)

#define FLAG_DATA_SACKED 0x20 /* New SACK. */ // 這是對數(shù)據(jù)的一個選擇確認(rèn)

#define FLAG_ECE 0x40 /* ECE in this ACK */ // 確認(rèn)中旅帶有ECE信息

#define FLAG_DATA_LOST 0x80 /* SACK detected data lossage. */ // SACK檢測到數(shù)據(jù)丟失

#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ // slowpath,需要做一些檢查

#define FLAG_ONLY_ORIG_SACKED 0x200 /* SACKs only non-rexmit sent before RTO */

#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ // snd-una改變

#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ // 包含DSACK信息

#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */

#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ // snd_una移動到一個sack中的一個位置

#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) // 表示數(shù)據(jù)確認(rèn)或者SYN確認(rèn)

#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) // 表示ACK是不重復(fù)的

#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE) // 表示是否在進入擁塞狀態(tài)的時候被alert(原因可能是SACK丟包或者路由器提示擁塞)

#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) // 選擇確認(rèn)

再看一下:

TCP_CA_Open:TCP連接的初始化的狀態(tài)。TCP連接會在慢啟動和擁塞避免階段(調(diào)用tcp_cong_avoid)增加擁塞窗口。每個接收到的ACK都要調(diào)用tcp_ack_is_dubious,檢查它是否可疑。如果是ACK可疑,就調(diào)用 tcp_fastretrans_alert()就切換到其他CA擁塞狀態(tài)。但是對于可疑的ACK,若窗口也允許增大(tcp_may_raise_cwnd),那么(tcp_fastretrans_alert)仍然可能增大擁塞窗口。

TCP_CA_Disorder:注意如果收到重復(fù)的ACK或者SACK,那么可能出現(xiàn)亂序情況,進入這個狀態(tài)處理。

TCP_CA_CWR:表示發(fā)生某些道路擁塞,需要減慢發(fā)送速度。

TCP_CA_Recovery:正在進行快速重傳丟失的數(shù)據(jù)包。

TCP_CA_Loss:超時重傳情況下,如果接收到的ACK與SACK信息不一樣,則阻塞丟包狀態(tài)。

staticinlineinttcp_ack_is_dubious(conststructsock?*sk,constintflag)

{

return(!(flag?&?FLAG_NOT_DUP)?||?(flag?&?FLAG_CA_ALERT)?||//?是重復(fù)的ACK???或者???在進入擁塞狀態(tài)的時候出現(xiàn)警告

inet_csk(sk)->icsk_ca_state?!=?TCP_CA_Open);//?或者擁塞狀態(tài)不是“增大擁塞窗口”狀態(tài)

}//?則這個ACK是可疑的,其實意思就是,不是一個正常的ACK,不能隨便增大擁塞窗口

static inline int tcp_ack_is_dubious(const struct sock *sk, const int flag)

{

return (!(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) || // 是重復(fù)的ACK 或者 在進入擁塞狀態(tài)的時候出現(xiàn)警告

inet_csk(sk)->icsk_ca_state != TCP_CA_Open); // 或者擁塞狀態(tài)不是“增大擁塞窗口”狀態(tài)

} // 則這個ACK是可疑的,其實意思就是,不是一個正常的ACK,不能隨便增大擁塞窗口

下面就兩條路:

1:如果被懷疑

2:如果沒有被懷疑

先看如果被懷疑了,那么:

先看函數(shù):tcp_may_raise_cwnd

staticinlineinttcp_may_raise_cwnd(conststructsock?*sk,constintflag)

{

conststructtcp_sock?*tp?=?tcp_sk(sk);

return(!(flag?&?FLAG_ECE)?||?tp->snd_cwnd?snd_ssthresh)?&&//?沒有其他阻塞??或者??(發(fā)送窗口小于門限&&不是Recovery?,也不是CWR)

!((1?<icsk_ca_state)?&?(TCPF_CA_Recovery?|?TCPF_CA_CWR));//?那么這樣還是可以增大窗口的嘛~~~~~?^_^

}

static inline int tcp_may_raise_cwnd(const struct sock *sk, const int flag)

{

const struct tcp_sock *tp = tcp_sk(sk);

return (!(flag & FLAG_ECE) || tp->snd_cwnd < tp->snd_ssthresh) && // 沒有其他阻塞 或者 (發(fā)送窗口小于門限&&不是Recovery ,也不是CWR)

!((1 << inet_csk(sk)->icsk_ca_state) & (TCPF_CA_Recovery | TCPF_CA_CWR)); // 那么這樣還是可以增大窗口的嘛~~~~~ ^_^

}

如果可以增大窗口,那么就需要使用tcp_cong_avoid執(zhí)行這個函數(shù)用來實現(xiàn)慢啟動和快速重傳擁塞避免算法:

這個函數(shù)也是在“沒有被懷疑”的情況下執(zhí)行的函數(shù),所以

如果沒有被懷疑,執(zhí)行的也是tcp_cong_avoid,一起解釋:

staticvoidtcp_cong_avoid(structsock?*sk,?u32?ack,?u32?in_flight)

{

conststructinet_connection_sock?*icsk?=?inet_csk(sk);

icsk->icsk_ca_ops->cong_avoid(sk,?ack,?in_flight);//?這才是重要處理函數(shù)

tcp_sk(sk)->snd_cwnd_stamp?=?tcp_time_stamp;//?發(fā)送窗口改變時間戳

}

static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)

{

const struct inet_connection_sock *icsk = inet_csk(sk);

icsk->icsk_ca_ops->cong_avoid(sk, ack, in_flight); // 這才是重要處理函數(shù)

tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp; // 發(fā)送窗口改變時間戳

}

我們看到上面說的擁塞結(jié)構(gòu)體的初始化:

structtcp_congestion_ops?tcp_init_congestion_ops??=?{

.name???????????="",

.owner??????????=?THIS_MODULE,

.ssthresh???????=?tcp_reno_ssthresh,

.cong_avoid?????=?tcp_reno_cong_avoid,//這個函數(shù)

.min_cwnd???????=?tcp_reno_min_cwnd,

};

struct tcp_congestion_ops tcp_init_congestion_ops = {

.name = "",

.owner = THIS_MODULE,

.ssthresh = tcp_reno_ssthresh,

.cong_avoid = tcp_reno_cong_avoid, //這個函數(shù)

.min_cwnd = tcp_reno_min_cwnd,

};

那么實際執(zhí)行的就是tcp_reno_cong_avoid函數(shù)!!!

----------------------------------------------------------------------------------------------------------------------------------

OK,下面再看看tcp_fastretrans_alert函數(shù):TCP擁塞狀態(tài)機主要是在tcp_fastretrans_alert()中實現(xiàn)的,只有在ACK被懷疑的時候才會執(zhí)行這個提醒函數(shù)

此函數(shù)被調(diào)用的條件也就是懷疑的條件:

1:進來一個ACK,但是狀態(tài)不是 Open

2:收到的是? ?SACK 、Duplicate ACK、ECN、ECE 等警告信息

到此為止,處理接收到的ACK基本結(jié)束。。。。

總結(jié)

以上是生活随笔為你收集整理的linux重置网络协议,Linux 内核网络协议栈 ------ tcp_ack 函数处理接收到的ACK包之后 ....的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。