1 | #include <net/tcp.h> |
---|
2 | #include <linux/module.h> |
---|
3 | |
---|
4 | int sysctl_tcp_max_ssthresh = 0; |
---|
5 | |
---|
6 | /* In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd (or alternative w) */ |
---|
7 | void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w) |
---|
8 | { |
---|
9 | if (tp->snd_cwnd_cnt >= w) { |
---|
10 | if (tp->snd_cwnd < tp->snd_cwnd_clamp) |
---|
11 | tp->snd_cwnd++; |
---|
12 | tp->snd_cwnd_cnt = 0; |
---|
13 | } else { |
---|
14 | tp->snd_cwnd_cnt++; |
---|
15 | } |
---|
16 | } |
---|
17 | |
---|
18 | static void exp_slow_start(struct tcp_sock *tp) |
---|
19 | { |
---|
20 | /* Handle cwnd manipulation for slow start here */ |
---|
21 | int cnt; /* increase in packets */ |
---|
22 | unsigned int delta = 0; |
---|
23 | u32 snd_cwnd = tp->snd_cwnd; |
---|
24 | |
---|
25 | if (unlikely(!snd_cwnd)) { |
---|
26 | printk("snd_cwnd is nul, please report this bug.\n"); |
---|
27 | snd_cwnd = 1U; |
---|
28 | } |
---|
29 | |
---|
30 | if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh) |
---|
31 | cnt = sysctl_tcp_max_ssthresh >> 1; /* limited slow start */ |
---|
32 | else |
---|
33 | cnt = snd_cwnd * 2; /* changed by Shufeng - exponential factor 3 increase */ |
---|
34 | |
---|
35 | tp->snd_cwnd_cnt += cnt; |
---|
36 | while (tp->snd_cwnd_cnt >= snd_cwnd) { |
---|
37 | tp->snd_cwnd_cnt -= snd_cwnd; |
---|
38 | delta++; |
---|
39 | } |
---|
40 | tp->snd_cwnd = min(snd_cwnd + delta, tp->snd_cwnd_clamp); |
---|
41 | } |
---|
42 | |
---|
43 | static void exp_cong_avoid(struct sock *sk, u32 adk, u32 in_flight) |
---|
44 | { |
---|
45 | /* Handle cwnd manipulation for congestion avoidance here */ |
---|
46 | struct tcp_sock *tp = tcp_sk(sk); |
---|
47 | |
---|
48 | if (!tcp_is_cwnd_limited(sk, in_flight)) |
---|
49 | return; |
---|
50 | |
---|
51 | /* In "safe" area, increase. */ |
---|
52 | if (tp->snd_cwnd <= tp->snd_ssthresh) |
---|
53 | exp_slow_start(tp); |
---|
54 | /* In dangerous area, increase slowly. */ |
---|
55 | else |
---|
56 | tcp_cong_avoid_ai(tp, tp->snd_cwnd); |
---|
57 | } |
---|
58 | |
---|
59 | static u32 exp_ssthresh(struct sock *sk) |
---|
60 | { |
---|
61 | /* Compute the appropriate value of ssthresh here */ |
---|
62 | const struct tcp_sock *tp = tcp_sk(sk); |
---|
63 | return max(tp->snd_cwnd*3/4, 2U); //changed by Shufeng |
---|
64 | } |
---|
65 | |
---|
66 | |
---|
67 | //See http://lwn.net/Articles/128681/ for more information |
---|
68 | /* |
---|
69 | * The start() method initializes the algorithm when a new batch of data |
---|
70 | * is being transmitted; this can happen for new sockets, or when one |
---|
71 | * has been idle for a while. |
---|
72 | * |
---|
73 | * The ssthresh() method calculates the "slow start threshold"; when the |
---|
74 | * congestion window is below that threshold, the connection is in slow |
---|
75 | * start mode rather than full congestion avoidance mode. This method is |
---|
76 | * called when congestion occurs. |
---|
77 | * |
---|
78 | * The actual initial window may be set by min_cwnd() to be less than |
---|
79 | * the threshold value as a starting point for the slow start algorithm. |
---|
80 | * |
---|
81 | * When an acknowledgment arrives from the remote end, the cong_avoid() |
---|
82 | * method is invoked; it may respond to successful packet delivery by |
---|
83 | * enlarging the congestion window. |
---|
84 | * |
---|
85 | * rtt_sample() tells the algorithm about a measured round-trip time - |
---|
86 | * the time taken between sending a packet and receiving the |
---|
87 | * corresponding acknowledgment. |
---|
88 | * |
---|
89 | * set_state() indicates that the TCP state of the socket has changed. |
---|
90 | * |
---|
91 | * Various events of interest can be communicated to the algorithm via |
---|
92 | * cwnd_event(). |
---|
93 | * |
---|
94 | * Sometimes, transient situations can cause the congestion window to be |
---|
95 | * reduced; the undo_cwnd() method can be called when such a situation |
---|
96 | * is detected to restore a larger window. |
---|
97 | * |
---|
98 | * The get_info() method can be used to make congestion avoidance |
---|
99 | * information available to user space. |
---|
100 | */ |
---|
101 | static struct tcp_congestion_ops tcp_exp __read_mostly = { |
---|
102 | .init = NULL, |
---|
103 | .ssthresh = exp_ssthresh, |
---|
104 | .cong_avoid = exp_cong_avoid, |
---|
105 | .min_cwnd = tcp_reno_min_cwnd, |
---|
106 | |
---|
107 | .owner = THIS_MODULE, |
---|
108 | .name = "exp" |
---|
109 | }; |
---|
110 | |
---|
111 | static int __init exp_register(void) |
---|
112 | { |
---|
113 | return tcp_register_congestion_control(&tcp_exp); |
---|
114 | } |
---|
115 | |
---|
116 | static void __exit exp_unregister(void) |
---|
117 | { |
---|
118 | tcp_unregister_congestion_control(&tcp_exp); |
---|
119 | } |
---|
120 | |
---|
121 | module_init(exp_register); |
---|
122 | module_exit(exp_unregister); |
---|
123 | |
---|
124 | MODULE_AUTHOR("Shufeng Huang"); |
---|
125 | MODULE_LICENSE("GPL"); |
---|
126 | MODULE_DESCRIPTION("Experimental TCP"); |
---|