aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_cong.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-11-09 19:35:15 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:21:49 -0500
commitce7bc3bf15cbf5dc5a5587ccb6b04c5b4dde4336 (patch)
tree20ccf7f98ac5d1aabbc706fa876e8f361219db97 /net/ipv4/tcp_cong.c
parent3ff825b28d3345ef381eceae22bf9d92231f23dc (diff)
[TCP]: Restrict congestion control choices.
Allow normal users to only choose among a restricted set of congestion control choices. The default is reno and what ever has been configured as default. But the policy can be changed by administrator at any time. For example, to allow any choice: cp /proc/sys/net/ipv4/tcp_available_congestion_control \ /proc/sys/net/ipv4/tcp_allowed_congestion_control 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.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index d846d7b95e1f..343d6197c92e 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name)
123#endif 123#endif
124 124
125 if (ca) { 125 if (ca) {
126 ca->non_restricted = 1; /* default is always allowed */
126 list_move(&ca->list, &tcp_cong_list); 127 list_move(&ca->list, &tcp_cong_list);
127 ret = 0; 128 ret = 0;
128 } 129 }
@@ -168,6 +169,64 @@ void tcp_get_default_congestion_control(char *name)
168 rcu_read_unlock(); 169 rcu_read_unlock();
169} 170}
170 171
172/* Built list of non-restricted congestion control values */
173void tcp_get_allowed_congestion_control(char *buf, size_t maxlen)
174{
175 struct tcp_congestion_ops *ca;
176 size_t offs = 0;
177
178 *buf = '\0';
179 rcu_read_lock();
180 list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
181 if (!ca->non_restricted)
182 continue;
183 offs += snprintf(buf + offs, maxlen - offs,
184 "%s%s",
185 offs == 0 ? "" : " ", ca->name);
186
187 }
188 rcu_read_unlock();
189}
190
191/* Change list of non-restricted congestion control */
192int tcp_set_allowed_congestion_control(char *val)
193{
194 struct tcp_congestion_ops *ca;
195 char *clone, *name;
196 int ret = 0;
197
198 clone = kstrdup(val, GFP_USER);
199 if (!clone)
200 return -ENOMEM;
201
202 spin_lock(&tcp_cong_list_lock);
203 /* pass 1 check for bad entries */
204 while ((name = strsep(&clone, " ")) && *name) {
205 ca = tcp_ca_find(name);
206 if (!ca) {
207 ret = -ENOENT;
208 goto out;
209 }
210 }
211
212 /* pass 2 clear */
213 list_for_each_entry_rcu(ca, &tcp_cong_list, list)
214 ca->non_restricted = 0;
215
216 /* pass 3 mark as allowed */
217 while ((name = strsep(&val, " ")) && *name) {
218 ca = tcp_ca_find(name);
219 WARN_ON(!ca);
220 if (ca)
221 ca->non_restricted = 1;
222 }
223out:
224 spin_unlock(&tcp_cong_list_lock);
225
226 return ret;
227}
228
229
171/* Change congestion control for socket */ 230/* Change congestion control for socket */
172int tcp_set_congestion_control(struct sock *sk, const char *name) 231int tcp_set_congestion_control(struct sock *sk, const char *name)
173{ 232{
@@ -183,6 +242,9 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
183 if (!ca) 242 if (!ca)
184 err = -ENOENT; 243 err = -ENOENT;
185 244
245 else if (!(ca->non_restricted || capable(CAP_NET_ADMIN)))
246 err = -EPERM;
247
186 else if (!try_module_get(ca->owner)) 248 else if (!try_module_get(ca->owner))
187 err = -EBUSY; 249 err = -EBUSY;
188 250
@@ -284,6 +346,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
284 346
285struct tcp_congestion_ops tcp_reno = { 347struct tcp_congestion_ops tcp_reno = {
286 .name = "reno", 348 .name = "reno",
349 .non_restricted = 1,
287 .owner = THIS_MODULE, 350 .owner = THIS_MODULE,
288 .ssthresh = tcp_reno_ssthresh, 351 .ssthresh = tcp_reno_ssthresh,
289 .cong_avoid = tcp_reno_cong_avoid, 352 .cong_avoid = tcp_reno_cong_avoid,