diff options
| author | Stephen Hemminger <shemminger@osdl.org> | 2005-06-23 20:37:36 -0700 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2005-06-23 20:37:36 -0700 | 
| commit | 5f8ef48d240963093451bcf83df89f1a1364f51d (patch) | |
| tree | cecb30c2f59778f7f509a84b3aa7ea097c3f2b27 /net/ipv4/tcp_cong.c | |
| parent | 51b0bdedb8e784d0d969a6b77151911130812400 (diff) | |
| download | olio-linux-3.10-5f8ef48d240963093451bcf83df89f1a1364f51d.tar.xz olio-linux-3.10-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 665394a63ae..4970d10a778 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);  |