diff -Nru a/Makefile b/Makefile --- a/Makefile Tue Nov 26 15:55:05 2002 +++ b/Makefile Tue Nov 26 15:55:05 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 19 -EXTRAVERSION = +EXTRAVERSION = -hstcp KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Tue Nov 26 15:55:05 2002 +++ b/include/linux/sysctl.h Tue Nov 26 15:55:05 2002 @@ -291,7 +291,8 @@ NET_IPV4_NONLOCAL_BIND=88, NET_IPV4_ICMP_RATELIMIT=89, NET_IPV4_ICMP_RATEMASK=90, - NET_TCP_TW_REUSE=91 + NET_TCP_TW_REUSE=91, + NET_TCP_ALTAIMD=95 }; enum { diff -Nru a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h Tue Nov 26 15:55:05 2002 +++ b/include/net/tcp.h Tue Nov 26 15:55:05 2002 @@ -147,6 +147,15 @@ return (lport & (tcp_bhash_size - 1)); } +#ifdef CONFIG_ALTAIMD +extern int sysctl_tcp_altAIMD; +struct hstcp_entry { + __u32 cwnd; + __u8 a_val; + __u8 b_val; +}; +#endif + /* This is a TIME_WAIT bucket. It works around the memory consumption * problems of sockets in such a state on heavily loaded servers, but * without violating the protocol specification. @@ -1072,6 +1081,30 @@ return tp->packets_out - tp->left_out + tp->retrans_out; } +/* Should we use the standard TCP AIMD behaviour? If so, the standard + * code path is used; this only changes things when non-standard AIMD + * (such as for Sally Floyd's HSTCP) is included in the kernel. + */ +#ifndef CONFIG_ALTAIMD +#define tcp_standard_aimd(tp,val1,val2) (val1) +#else +static inline int __tcp_standard_aimd(struct tcp_opt *tp) +{ + extern struct hstcp_entry hstcp_table[]; + return ((!sysctl_tcp_altAIMD) || + (sysctl_tcp_altAIMD && (tp->snd_cwnd < hstcp_table[0].cwnd))); +} +#define tcp_standard_aimd(tp,val1,val2) \ + ((__tcp_standard_aimd(tp)) ? (val1) : (val2)) + +extern struct hstcp_entry get_hstcp_val(struct tcp_opt *tp); + +static inline __u32 tcp_var_reduce(struct tcp_opt *tp) +{ + return (tp->snd_cwnd * (256 - get_hstcp_val(tp).b_val)) >> 8; +} +#endif + /* Recalculate snd_ssthresh, we want to set it to: * * one half the current congestion window, but no @@ -1079,7 +1112,8 @@ */ static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) { - return max(tp->snd_cwnd >> 1U, 2U); + return tcp_standard_aimd(tp, max(tp->snd_cwnd >> 1U, 2U), + max(tcp_var_reduce(tp), 2U)); } /* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. diff -Nru a/net/ipv4/Config.in b/net/ipv4/Config.in --- a/net/ipv4/Config.in Tue Nov 26 15:55:05 2002 +++ b/net/ipv4/Config.in Tue Nov 26 15:55:05 2002 @@ -40,6 +40,12 @@ bool ' IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD fi bool ' IP: TCP Explicit Congestion Notification support' CONFIG_INET_ECN +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' IP: High-Speed TCP [Sally Floyd] available (EXPERIMENTAL)' CONFIG_ALTAIMD + if [ "$CONFIG_ALTAIMD" = "y" ]; then + bool ' IP: High-Speed TCP on by default' CONFIG_ALTAIMD_ON + fi +fi bool ' IP: TCP syncookie support (disabled per default)' CONFIG_SYN_COOKIES if [ "$CONFIG_NETFILTER" != "n" ]; then source net/ipv4/netfilter/Config.in diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c --- a/net/ipv4/sysctl_net_ipv4.c Tue Nov 26 15:55:05 2002 +++ b/net/ipv4/sysctl_net_ipv4.c Tue Nov 26 15:55:05 2002 @@ -221,6 +221,10 @@ &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_TCP_TW_REUSE, "tcp_tw_reuse", &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_ALTAIMD + {NET_TCP_ALTAIMD, "tcp_altAIMD", + &sysctl_tcp_altAIMD, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif {0} }; diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c --- a/net/ipv4/tcp_input.c Tue Nov 26 15:55:05 2002 +++ b/net/ipv4/tcp_input.c Tue Nov 26 15:55:05 2002 @@ -87,6 +87,107 @@ int sysctl_tcp_rfc1337 = 0; int sysctl_tcp_max_orphans = NR_FILE; +#ifdef CONFIG_ALTAIMD +#ifdef CONFIG_ALTAIMD_ON +int sysctl_tcp_altAIMD = 1; +#else +int sysctl_tcp_altAIMD = 0; +#endif + +struct hstcp_entry hstcp_table[] = { +{38, 1, 128}, +{118, 2, 112}, +{221, 3, 104}, +{347, 4, 98}, +{495, 5, 93}, +{663, 6, 89}, +{851, 7, 86}, +{1058, 8, 83}, +{1284, 9, 81}, +{1529, 10, 78}, +{1793, 11, 76}, +{2076, 12, 74}, +{2378, 13, 72}, +{2699, 14, 71}, +{3039, 15, 69}, +{3399, 16, 68}, +{3778, 17, 66}, +{4177, 18, 65}, +{4596, 19, 64}, +{5036, 20, 62}, +{5497, 21, 61}, +{5979, 22, 60}, +{6483, 23, 59}, +{7009, 24, 58}, +{7558, 25, 57}, +{8130, 26, 56}, +{8726, 27, 55}, +{9346, 28, 54}, +{9991, 29, 53}, +{10661, 30, 52}, +{11358, 31, 52}, +{12082, 32, 51}, +{12834, 33, 50}, +{13614, 34, 49}, +{14424, 35, 48}, +{15265, 36, 48}, +{16137, 37, 47}, +{17042, 38, 46}, +{17981, 39, 45}, +{18955, 40, 45}, +{19965, 41, 44}, +{21013, 42, 43}, +{22101, 43, 43}, +{23230, 44, 42}, +{24402, 45, 41}, +{25618, 46, 41}, +{26881, 47, 40}, +{28193, 48, 39}, +{29557, 49, 39}, +{30975, 50, 38}, +{32450, 51, 38}, +{33986, 52, 37}, +{35586, 53, 36}, +{37253, 54, 36}, +{38992, 55, 35}, +{40808, 56, 35}, +{42707, 57, 34}, +{44694, 58, 33}, +{46776, 59, 33}, +{48961, 60, 32}, +{51258, 61, 32}, +{53677, 62, 31}, +{56230, 63, 30}, +{58932, 64, 30}, +{61799, 65, 29}, +{64851, 66, 28}, +{68113, 67, 28}, +{71617, 68, 27}, +{75401, 69, 26}, +{79517, 70, 26}, +{84035, 71, 25}, +{89053, 72, 24}, +{94717, 73, 23}, +}; +static short hstcp_max_entry=72; + +struct hstcp_entry get_hstcp_val(struct tcp_opt *tp) { + short left,right,mid; + __u32 this_cwnd = tp->snd_cwnd; + left = 0; + right = hstcp_max_entry; + while (right-left) { + mid = (left + right)>>1; + if (hstcp_table[mid].cwnd < this_cwnd) { + left = mid + 1; + } else { + right = mid; + } + } + return hstcp_table[right]; +} +#endif + #define FLAG_DATA 0x01 /* Incoming frame contained data. */ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ #define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ @@ -1693,6 +1794,13 @@ tcp_ack_no_tstamp(tp, seq_rtt, flag); } +static inline int tcp_should_inc_cwnd(struct tcp_opt *tp) +{ + return tcp_standard_aimd(tp, (tp->snd_cwnd_cnt >= tp->snd_cwnd), + ((tp->snd_cwnd_cnt * get_hstcp_val(tp).a_val) + >= tp->snd_cwnd)); +} + /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. */ @@ -1706,7 +1814,7 @@ /* In dangerous area, increase slowly. * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd */ - if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { + if (tcp_should_inc_cwnd(tp)) { if (tp->snd_cwnd < tp->snd_cwnd_clamp) tp->snd_cwnd++; tp->snd_cwnd_cnt=0; diff -Nru a/net/netsyms.c b/net/netsyms.c --- a/net/netsyms.c Tue Nov 26 15:55:05 2002 +++ b/net/netsyms.c Tue Nov 26 15:55:05 2002 @@ -530,6 +530,9 @@ EXPORT_SYMBOL(sysctl_rmem_max); #ifdef CONFIG_INET EXPORT_SYMBOL(sysctl_ip_default_ttl); +#ifdef CONFIG_ALTAIMD +EXPORT_SYMBOL(sysctl_tcp_altAIMD); +#endif #endif #endif