0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <linux/mm.h>
0026 #include <linux/module.h>
0027 #include <linux/skbuff.h>
0028 #include <linux/inet_diag.h>
0029 #include <net/tcp.h>
0030
0031
0032 struct westwood {
0033 u32 bw_ns_est;
0034 u32 bw_est;
0035 u32 rtt_win_sx;
0036 u32 bk;
0037 u32 snd_una;
0038 u32 cumul_ack;
0039 u32 accounted;
0040 u32 rtt;
0041 u32 rtt_min;
0042 u8 first_ack;
0043 u8 reset_rtt_min;
0044 };
0045
0046
0047 #define TCP_WESTWOOD_RTT_MIN (HZ/20)
0048 #define TCP_WESTWOOD_INIT_RTT (20*HZ)
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 static void tcp_westwood_init(struct sock *sk)
0062 {
0063 struct westwood *w = inet_csk_ca(sk);
0064
0065 w->bk = 0;
0066 w->bw_ns_est = 0;
0067 w->bw_est = 0;
0068 w->accounted = 0;
0069 w->cumul_ack = 0;
0070 w->reset_rtt_min = 1;
0071 w->rtt_min = w->rtt = TCP_WESTWOOD_INIT_RTT;
0072 w->rtt_win_sx = tcp_jiffies32;
0073 w->snd_una = tcp_sk(sk)->snd_una;
0074 w->first_ack = 1;
0075 }
0076
0077
0078
0079
0080
0081 static inline u32 westwood_do_filter(u32 a, u32 b)
0082 {
0083 return ((7 * a) + b) >> 3;
0084 }
0085
0086 static void westwood_filter(struct westwood *w, u32 delta)
0087 {
0088
0089 if (w->bw_ns_est == 0 && w->bw_est == 0) {
0090 w->bw_ns_est = w->bk / delta;
0091 w->bw_est = w->bw_ns_est;
0092 } else {
0093 w->bw_ns_est = westwood_do_filter(w->bw_ns_est, w->bk / delta);
0094 w->bw_est = westwood_do_filter(w->bw_est, w->bw_ns_est);
0095 }
0096 }
0097
0098
0099
0100
0101
0102
0103 static void tcp_westwood_pkts_acked(struct sock *sk,
0104 const struct ack_sample *sample)
0105 {
0106 struct westwood *w = inet_csk_ca(sk);
0107
0108 if (sample->rtt_us > 0)
0109 w->rtt = usecs_to_jiffies(sample->rtt_us);
0110 }
0111
0112
0113
0114
0115
0116
0117 static void westwood_update_window(struct sock *sk)
0118 {
0119 struct westwood *w = inet_csk_ca(sk);
0120 s32 delta = tcp_jiffies32 - w->rtt_win_sx;
0121
0122
0123
0124
0125
0126 if (w->first_ack) {
0127 w->snd_una = tcp_sk(sk)->snd_una;
0128 w->first_ack = 0;
0129 }
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 if (w->rtt && delta > max_t(u32, w->rtt, TCP_WESTWOOD_RTT_MIN)) {
0141 westwood_filter(w, delta);
0142
0143 w->bk = 0;
0144 w->rtt_win_sx = tcp_jiffies32;
0145 }
0146 }
0147
0148 static inline void update_rtt_min(struct westwood *w)
0149 {
0150 if (w->reset_rtt_min) {
0151 w->rtt_min = w->rtt;
0152 w->reset_rtt_min = 0;
0153 } else
0154 w->rtt_min = min(w->rtt, w->rtt_min);
0155 }
0156
0157
0158
0159
0160
0161
0162
0163 static inline void westwood_fast_bw(struct sock *sk)
0164 {
0165 const struct tcp_sock *tp = tcp_sk(sk);
0166 struct westwood *w = inet_csk_ca(sk);
0167
0168 westwood_update_window(sk);
0169
0170 w->bk += tp->snd_una - w->snd_una;
0171 w->snd_una = tp->snd_una;
0172 update_rtt_min(w);
0173 }
0174
0175
0176
0177
0178
0179
0180 static inline u32 westwood_acked_count(struct sock *sk)
0181 {
0182 const struct tcp_sock *tp = tcp_sk(sk);
0183 struct westwood *w = inet_csk_ca(sk);
0184
0185 w->cumul_ack = tp->snd_una - w->snd_una;
0186
0187
0188
0189
0190 if (!w->cumul_ack) {
0191 w->accounted += tp->mss_cache;
0192 w->cumul_ack = tp->mss_cache;
0193 }
0194
0195 if (w->cumul_ack > tp->mss_cache) {
0196
0197 if (w->accounted >= w->cumul_ack) {
0198 w->accounted -= w->cumul_ack;
0199 w->cumul_ack = tp->mss_cache;
0200 } else {
0201 w->cumul_ack -= w->accounted;
0202 w->accounted = 0;
0203 }
0204 }
0205
0206 w->snd_una = tp->snd_una;
0207
0208 return w->cumul_ack;
0209 }
0210
0211
0212
0213
0214
0215
0216
0217 static u32 tcp_westwood_bw_rttmin(const struct sock *sk)
0218 {
0219 const struct tcp_sock *tp = tcp_sk(sk);
0220 const struct westwood *w = inet_csk_ca(sk);
0221
0222 return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2);
0223 }
0224
0225 static void tcp_westwood_ack(struct sock *sk, u32 ack_flags)
0226 {
0227 if (ack_flags & CA_ACK_SLOWPATH) {
0228 struct westwood *w = inet_csk_ca(sk);
0229
0230 westwood_update_window(sk);
0231 w->bk += westwood_acked_count(sk);
0232
0233 update_rtt_min(w);
0234 return;
0235 }
0236
0237 westwood_fast_bw(sk);
0238 }
0239
0240 static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
0241 {
0242 struct tcp_sock *tp = tcp_sk(sk);
0243 struct westwood *w = inet_csk_ca(sk);
0244
0245 switch (event) {
0246 case CA_EVENT_COMPLETE_CWR:
0247 tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
0248 tcp_snd_cwnd_set(tp, tp->snd_ssthresh);
0249 break;
0250 case CA_EVENT_LOSS:
0251 tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
0252
0253 w->reset_rtt_min = 1;
0254 break;
0255 default:
0256
0257 break;
0258 }
0259 }
0260
0261
0262 static size_t tcp_westwood_info(struct sock *sk, u32 ext, int *attr,
0263 union tcp_cc_info *info)
0264 {
0265 const struct westwood *ca = inet_csk_ca(sk);
0266
0267 if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
0268 info->vegas.tcpv_enabled = 1;
0269 info->vegas.tcpv_rttcnt = 0;
0270 info->vegas.tcpv_rtt = jiffies_to_usecs(ca->rtt);
0271 info->vegas.tcpv_minrtt = jiffies_to_usecs(ca->rtt_min);
0272
0273 *attr = INET_DIAG_VEGASINFO;
0274 return sizeof(struct tcpvegas_info);
0275 }
0276 return 0;
0277 }
0278
0279 static struct tcp_congestion_ops tcp_westwood __read_mostly = {
0280 .init = tcp_westwood_init,
0281 .ssthresh = tcp_reno_ssthresh,
0282 .cong_avoid = tcp_reno_cong_avoid,
0283 .undo_cwnd = tcp_reno_undo_cwnd,
0284 .cwnd_event = tcp_westwood_event,
0285 .in_ack_event = tcp_westwood_ack,
0286 .get_info = tcp_westwood_info,
0287 .pkts_acked = tcp_westwood_pkts_acked,
0288
0289 .owner = THIS_MODULE,
0290 .name = "westwood"
0291 };
0292
0293 static int __init tcp_westwood_register(void)
0294 {
0295 BUILD_BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE);
0296 return tcp_register_congestion_control(&tcp_westwood);
0297 }
0298
0299 static void __exit tcp_westwood_unregister(void)
0300 {
0301 tcp_unregister_congestion_control(&tcp_westwood);
0302 }
0303
0304 module_init(tcp_westwood_register);
0305 module_exit(tcp_westwood_unregister);
0306
0307 MODULE_AUTHOR("Stephen Hemminger, Angelo Dell'Aera");
0308 MODULE_LICENSE("GPL");
0309 MODULE_DESCRIPTION("TCP Westwood+");