diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2005-06-24 05:37:36 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-06-24 05:37:36 +0200 |
commit | 5f8ef48d240963093451bcf83df89f1a1364f51d (patch) | |
tree | cecb30c2f59778f7f509a84b3aa7ea097c3f2b27 /net/ipv4/tcp_cong.c | |
parent | [NET]: Separate two usages of netdev_max_backlog. (diff) | |
download | linux-5f8ef48d240963093451bcf83df89f1a1364f51d.tar.xz linux-5f8ef48d240963093451bcf83df89f1a1364f51d.zip |
[TCP]: Allow choosing TCP congestion control via sockopt.
Allow using setsockopt to set TCP congestion control to use on a per
socket basis.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_cong.c')
-rw-r--r-- | net/ipv4/tcp_cong.c | 46 |
1 files changed, 44 insertions, 2 deletions
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 665394a63ae4..4970d10a7785 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -21,7 +21,7 @@ static struct tcp_congestion_ops *tcp_ca_find(const char *name) { struct tcp_congestion_ops *e; - list_for_each_entry(e, &tcp_cong_list, list) { + list_for_each_entry_rcu(e, &tcp_cong_list, list) { if (strcmp(e->name, name) == 0) return e; } @@ -77,6 +77,9 @@ void tcp_init_congestion_control(struct tcp_sock *tp) { struct tcp_congestion_ops *ca; + if (tp->ca_ops != &tcp_init_congestion_ops) + return; + rcu_read_lock(); list_for_each_entry_rcu(ca, &tcp_cong_list, list) { if (try_module_get(ca->owner)) { @@ -139,6 +142,34 @@ void tcp_get_default_congestion_control(char *name) rcu_read_unlock(); } +/* Change congestion control for socket */ +int tcp_set_congestion_control(struct tcp_sock *tp, const char *name) +{ + struct tcp_congestion_ops *ca; + int err = 0; + + rcu_read_lock(); + ca = tcp_ca_find(name); + if (ca == tp->ca_ops) + goto out; + + if (!ca) + err = -ENOENT; + + else if (!try_module_get(ca->owner)) + err = -EBUSY; + + else { + tcp_cleanup_congestion_control(tp); + tp->ca_ops = ca; + if (tp->ca_ops->init) + tp->ca_ops->init(tp); + } + out: + rcu_read_unlock(); + return err; +} + /* * TCP Reno congestion control * This is special case used for fallback as well. @@ -192,4 +223,15 @@ struct tcp_congestion_ops tcp_reno = { .min_cwnd = tcp_reno_min_cwnd, }; -EXPORT_SYMBOL_GPL(tcp_reno); +/* Initial congestion control used (until SYN) + * really reno under another name so we can tell difference + * during tcp_set_default_congestion_control + */ +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, +}; +EXPORT_SYMBOL_GPL(tcp_init_congestion_ops); |