diff options
author | Ying Xue <ying.xue@windriver.com> | 2013-06-17 10:54:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-17 18:53:00 -0400 |
commit | cc79dd1ba9c1021c2ac6ae200a65ec38ee8db351 (patch) | |
tree | 86ffd4e43a1fb2d833a750ea713ce81b0af5df63 /net/tipc | |
parent | 8941bbcd572a8860ad03c76e2f3d1dafa820b842 (diff) |
tipc: change socket buffer overflow control to respect sk_rcvbuf
As per feedback from the netdev community, we change the buffer
overflow protection algorithm in receiving sockets so that it
always respects the nominal upper limit set in sk_rcvbuf.
Instead of scaling up from a small sk_rcvbuf value, which leads to
violation of the configured sk_rcvbuf limit, we now calculate the
weighted per-message limit by scaling down from a much bigger value,
still in the same field, according to the importance priority of the
received message.
To allow for administrative tunability of the socket receive buffer
size, we create a tipc_rmem sysctl variable to allow the user to
configure an even bigger value via sysctl command. It is a size of
three (min/default/max) to be consistent with things like tcp_rmem.
By default, the value initialized in tipc_rmem[1] is equal to the
receive socket size needed by a TIPC_CRITICAL_IMPORTANCE message.
This value is also set as the default value of sk_rcvbuf.
Originally-by: Jon Maloy <jon.maloy@ericsson.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Jon Maloy <jon.maloy@ericsson.com>
[Ying: added sysctl variation to Jon's original patch]
Signed-off-by: Ying Xue <ying.xue@windriver.com>
[PG: don't compile sysctl.c if not config'd; add Documentation]
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/Makefile | 1 | ||||
-rw-r--r-- | net/tipc/core.c | 12 | ||||
-rw-r--r-- | net/tipc/core.h | 9 | ||||
-rw-r--r-- | net/tipc/port.h | 2 | ||||
-rw-r--r-- | net/tipc/socket.c | 19 | ||||
-rw-r--r-- | net/tipc/sysctl.c | 64 |
6 files changed, 96 insertions, 11 deletions
diff --git a/net/tipc/Makefile b/net/tipc/Makefile index 4df8e02d9008..02636d0a90cf 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile | |||
@@ -11,3 +11,4 @@ tipc-y += addr.o bcast.o bearer.o config.o \ | |||
11 | socket.o log.o eth_media.o | 11 | socket.o log.o eth_media.o |
12 | 12 | ||
13 | tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o | 13 | tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o |
14 | tipc-$(CONFIG_SYSCTL) += sysctl.o | ||
diff --git a/net/tipc/core.c b/net/tipc/core.c index 7ec2c1eb94f1..b0e42a087291 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "name_table.h" | 39 | #include "name_table.h" |
40 | #include "subscr.h" | 40 | #include "subscr.h" |
41 | #include "config.h" | 41 | #include "config.h" |
42 | #include "port.h" | ||
42 | 43 | ||
43 | #include <linux/module.h> | 44 | #include <linux/module.h> |
44 | 45 | ||
@@ -50,7 +51,7 @@ u32 tipc_own_addr __read_mostly; | |||
50 | int tipc_max_ports __read_mostly; | 51 | int tipc_max_ports __read_mostly; |
51 | int tipc_net_id __read_mostly; | 52 | int tipc_net_id __read_mostly; |
52 | int tipc_remote_management __read_mostly; | 53 | int tipc_remote_management __read_mostly; |
53 | 54 | int sysctl_tipc_rmem[3] __read_mostly; /* min/default/max */ | |
54 | 55 | ||
55 | /** | 56 | /** |
56 | * tipc_buf_acquire - creates a TIPC message buffer | 57 | * tipc_buf_acquire - creates a TIPC message buffer |
@@ -118,6 +119,7 @@ static void tipc_core_stop(void) | |||
118 | tipc_nametbl_stop(); | 119 | tipc_nametbl_stop(); |
119 | tipc_ref_table_stop(); | 120 | tipc_ref_table_stop(); |
120 | tipc_socket_stop(); | 121 | tipc_socket_stop(); |
122 | tipc_unregister_sysctl(); | ||
121 | } | 123 | } |
122 | 124 | ||
123 | /** | 125 | /** |
@@ -142,13 +144,14 @@ static int tipc_core_start(void) | |||
142 | res = tipc_netlink_start(); | 144 | res = tipc_netlink_start(); |
143 | if (!res) | 145 | if (!res) |
144 | res = tipc_socket_init(); | 146 | res = tipc_socket_init(); |
147 | if (!res) | ||
148 | res = tipc_register_sysctl(); | ||
145 | if (res) | 149 | if (res) |
146 | tipc_core_stop(); | 150 | tipc_core_stop(); |
147 | 151 | ||
148 | return res; | 152 | return res; |
149 | } | 153 | } |
150 | 154 | ||
151 | |||
152 | static int __init tipc_init(void) | 155 | static int __init tipc_init(void) |
153 | { | 156 | { |
154 | int res; | 157 | int res; |
@@ -160,6 +163,11 @@ static int __init tipc_init(void) | |||
160 | tipc_max_ports = CONFIG_TIPC_PORTS; | 163 | tipc_max_ports = CONFIG_TIPC_PORTS; |
161 | tipc_net_id = 4711; | 164 | tipc_net_id = 4711; |
162 | 165 | ||
166 | sysctl_tipc_rmem[0] = CONN_OVERLOAD_LIMIT >> 4 << TIPC_LOW_IMPORTANCE; | ||
167 | sysctl_tipc_rmem[1] = CONN_OVERLOAD_LIMIT >> 4 << | ||
168 | TIPC_CRITICAL_IMPORTANCE; | ||
169 | sysctl_tipc_rmem[2] = CONN_OVERLOAD_LIMIT; | ||
170 | |||
163 | res = tipc_core_start(); | 171 | res = tipc_core_start(); |
164 | if (res) | 172 | if (res) |
165 | pr_err("Unable to start in single node mode\n"); | 173 | pr_err("Unable to start in single node mode\n"); |
diff --git a/net/tipc/core.h b/net/tipc/core.h index 0207db04179a..fe7f2b7c19fe 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h | |||
@@ -80,6 +80,7 @@ extern u32 tipc_own_addr __read_mostly; | |||
80 | extern int tipc_max_ports __read_mostly; | 80 | extern int tipc_max_ports __read_mostly; |
81 | extern int tipc_net_id __read_mostly; | 81 | extern int tipc_net_id __read_mostly; |
82 | extern int tipc_remote_management __read_mostly; | 82 | extern int tipc_remote_management __read_mostly; |
83 | extern int sysctl_tipc_rmem[3] __read_mostly; | ||
83 | 84 | ||
84 | /* | 85 | /* |
85 | * Other global variables | 86 | * Other global variables |
@@ -97,6 +98,14 @@ extern void tipc_netlink_stop(void); | |||
97 | extern int tipc_socket_init(void); | 98 | extern int tipc_socket_init(void); |
98 | extern void tipc_socket_stop(void); | 99 | extern void tipc_socket_stop(void); |
99 | 100 | ||
101 | #ifdef CONFIG_SYSCTL | ||
102 | extern int tipc_register_sysctl(void); | ||
103 | extern void tipc_unregister_sysctl(void); | ||
104 | #else | ||
105 | #define tipc_register_sysctl() 0 | ||
106 | #define tipc_unregister_sysctl() | ||
107 | #endif | ||
108 | |||
100 | /* | 109 | /* |
101 | * TIPC timer and signal code | 110 | * TIPC timer and signal code |
102 | */ | 111 | */ |
diff --git a/net/tipc/port.h b/net/tipc/port.h index fb66e2e5f4d1..2485649c408a 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h | |||
@@ -43,6 +43,8 @@ | |||
43 | #include "node_subscr.h" | 43 | #include "node_subscr.h" |
44 | 44 | ||
45 | #define TIPC_FLOW_CONTROL_WIN 512 | 45 | #define TIPC_FLOW_CONTROL_WIN 512 |
46 | #define CONN_OVERLOAD_LIMIT ((TIPC_FLOW_CONTROL_WIN * 2 + 1) * \ | ||
47 | SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE)) | ||
46 | 48 | ||
47 | typedef void (*tipc_msg_err_event) (void *usr_handle, u32 portref, | 49 | typedef void (*tipc_msg_err_event) (void *usr_handle, u32 portref, |
48 | struct sk_buff **buf, unsigned char const *data, | 50 | struct sk_buff **buf, unsigned char const *data, |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 515ce38e4f4c..aba4255f297b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -43,8 +43,6 @@ | |||
43 | #define SS_LISTENING -1 /* socket is listening */ | 43 | #define SS_LISTENING -1 /* socket is listening */ |
44 | #define SS_READY -2 /* socket is connectionless */ | 44 | #define SS_READY -2 /* socket is connectionless */ |
45 | 45 | ||
46 | #define CONN_OVERLOAD_LIMIT ((TIPC_FLOW_CONTROL_WIN * 2 + 1) * \ | ||
47 | SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE)) | ||
48 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ | 46 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ |
49 | 47 | ||
50 | struct tipc_sock { | 48 | struct tipc_sock { |
@@ -203,6 +201,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol, | |||
203 | 201 | ||
204 | sock_init_data(sock, sk); | 202 | sock_init_data(sock, sk); |
205 | sk->sk_backlog_rcv = backlog_rcv; | 203 | sk->sk_backlog_rcv = backlog_rcv; |
204 | sk->sk_rcvbuf = sysctl_tipc_rmem[1]; | ||
206 | sk->sk_data_ready = tipc_data_ready; | 205 | sk->sk_data_ready = tipc_data_ready; |
207 | sk->sk_write_space = tipc_write_space; | 206 | sk->sk_write_space = tipc_write_space; |
208 | tipc_sk(sk)->p = tp_ptr; | 207 | tipc_sk(sk)->p = tp_ptr; |
@@ -1233,10 +1232,10 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) | |||
1233 | * For all connectionless messages, by default new queue limits are | 1232 | * For all connectionless messages, by default new queue limits are |
1234 | * as belows: | 1233 | * as belows: |
1235 | * | 1234 | * |
1236 | * TIPC_LOW_IMPORTANCE (5MB) | 1235 | * TIPC_LOW_IMPORTANCE (4 MB) |
1237 | * TIPC_MEDIUM_IMPORTANCE (10MB) | 1236 | * TIPC_MEDIUM_IMPORTANCE (8 MB) |
1238 | * TIPC_HIGH_IMPORTANCE (20MB) | 1237 | * TIPC_HIGH_IMPORTANCE (16 MB) |
1239 | * TIPC_CRITICAL_IMPORTANCE (40MB) | 1238 | * TIPC_CRITICAL_IMPORTANCE (32 MB) |
1240 | * | 1239 | * |
1241 | * Returns overload limit according to corresponding message importance | 1240 | * Returns overload limit according to corresponding message importance |
1242 | */ | 1241 | */ |
@@ -1246,9 +1245,10 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) | |||
1246 | unsigned int limit; | 1245 | unsigned int limit; |
1247 | 1246 | ||
1248 | if (msg_connected(msg)) | 1247 | if (msg_connected(msg)) |
1249 | limit = CONN_OVERLOAD_LIMIT; | 1248 | limit = sysctl_tipc_rmem[2]; |
1250 | else | 1249 | else |
1251 | limit = sk->sk_rcvbuf << (msg_importance(msg) + 5); | 1250 | limit = sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << |
1251 | msg_importance(msg); | ||
1252 | return limit; | 1252 | return limit; |
1253 | } | 1253 | } |
1254 | 1254 | ||
@@ -1847,7 +1847,8 @@ static const struct net_proto_family tipc_family_ops = { | |||
1847 | static struct proto tipc_proto = { | 1847 | static struct proto tipc_proto = { |
1848 | .name = "TIPC", | 1848 | .name = "TIPC", |
1849 | .owner = THIS_MODULE, | 1849 | .owner = THIS_MODULE, |
1850 | .obj_size = sizeof(struct tipc_sock) | 1850 | .obj_size = sizeof(struct tipc_sock), |
1851 | .sysctl_rmem = sysctl_tipc_rmem | ||
1851 | }; | 1852 | }; |
1852 | 1853 | ||
1853 | /** | 1854 | /** |
diff --git a/net/tipc/sysctl.c b/net/tipc/sysctl.c new file mode 100644 index 000000000000..f3fef93325a8 --- /dev/null +++ b/net/tipc/sysctl.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * net/tipc/sysctl.c: sysctl interface to TIPC subsystem | ||
3 | * | ||
4 | * Copyright (c) 2013, Wind River Systems | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * 3. Neither the names of the copyright holders nor the names of its | ||
16 | * contributors may be used to endorse or promote products derived from | ||
17 | * this software without specific prior written permission. | ||
18 | * | ||
19 | * Alternatively, this software may be distributed under the terms of the | ||
20 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
21 | * Software Foundation. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
33 | * POSSIBILITY OF SUCH DAMAGE. | ||
34 | */ | ||
35 | |||
36 | #include "core.h" | ||
37 | |||
38 | #include <linux/sysctl.h> | ||
39 | |||
40 | static struct ctl_table_header *tipc_ctl_hdr; | ||
41 | |||
42 | static struct ctl_table tipc_table[] = { | ||
43 | { | ||
44 | .procname = "tipc_rmem", | ||
45 | .data = &sysctl_tipc_rmem, | ||
46 | .maxlen = sizeof(sysctl_tipc_rmem), | ||
47 | .mode = 0644, | ||
48 | .proc_handler = proc_dointvec, | ||
49 | }, | ||
50 | {} | ||
51 | }; | ||
52 | |||
53 | int tipc_register_sysctl(void) | ||
54 | { | ||
55 | tipc_ctl_hdr = register_net_sysctl(&init_net, "net/tipc", tipc_table); | ||
56 | if (tipc_ctl_hdr == NULL) | ||
57 | return -ENOMEM; | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | void tipc_unregister_sysctl(void) | ||
62 | { | ||
63 | unregister_net_sysctl_table(tipc_ctl_hdr); | ||
64 | } | ||