summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-04-23 22:32:11 -0700
committerDavid S. Miller <davem@davemloft.net>2007-04-23 22:32:11 -0700
commit4d4d3d1e8807d6aa9822eeedf7fe8500e1b7e38d (patch)
tree3a02563966b1f5f6c047bb340108251508318b0a
parentc445a31cd7f469d77acc37538ab43a99530968b8 (diff)
downloadlinux-stable-4d4d3d1e8807d6aa9822eeedf7fe8500e1b7e38d.tar.gz
linux-stable-4d4d3d1e8807d6aa9822eeedf7fe8500e1b7e38d.tar.bz2
linux-stable-4d4d3d1e8807d6aa9822eeedf7fe8500e1b7e38d.zip
[TCP]: Congestion control initialization.
Change to defer congestion control initialization. If setsockopt() was used to change TCP_CONGESTION before connection is established, then protocols that use sequence numbers to keep track of one RTT interval (vegas, illinois, ...) get confused. Change the init hook to be called after handshake. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/tcp_cong.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 5c8caf4a1244..34ae3f13483a 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -77,18 +77,19 @@ void tcp_init_congestion_control(struct sock *sk)
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_congestion_ops *ca;
- if (icsk->icsk_ca_ops != &tcp_init_congestion_ops)
- return;
+ /* if no choice made yet assign the current value set as default */
+ if (icsk->icsk_ca_ops == &tcp_init_congestion_ops) {
+ 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;
+ }
- 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();
}
- rcu_read_unlock();
if (icsk->icsk_ca_ops->init)
icsk->icsk_ca_ops->init(sk);
@@ -236,6 +237,7 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
rcu_read_lock();
ca = tcp_ca_find(name);
+
/* no change asking for existing value */
if (ca == icsk->icsk_ca_ops)
goto out;
@@ -261,7 +263,8 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
else {
tcp_cleanup_congestion_control(sk);
icsk->icsk_ca_ops = ca;
- if (icsk->icsk_ca_ops->init)
+
+ if (sk->sk_state != TCP_CLOSE && icsk->icsk_ca_ops->init)
icsk->icsk_ca_ops->init(sk);
}
out: