Browse code

sctp: retransmission options

- added new config and runtime options for controlling the
retransmissions at the sctp protocol level:
sctp_srto_initial - initial value of the retr. timeout used in
RTO calculations.
sctp_srto_max - maximum value of the retr. timeout (RTO).
sctp_srto_min - minimum value of the retr. timeout (RTO).
- on startup get the OS defaults for the sctp options so that
sercmd core.sctp_options always displays the options in use
(even if they haven't been "manually").

Andrei Pelinescu-Onciul authored on 29/05/2009 12:24:58
Showing 8 changed files
... ...
@@ -271,7 +271,7 @@ new config variables:
271 271
   sctp_socket_rcvbuf = number - size for the sctp socket receive buffer
272 272
   sctp_socket_sndbuf = number - size for the sctp socket send buffer
273 273
   sctp_autoclose = seconds - number of seconds before autoclosing an idle
274
-                   assocation (default: 180 s).
274
+                   association (default: 180 s).
275 275
                    Can be changed at runtime, but it will affect only new
276 276
                    associations. E.g.:
277 277
                    $ sercmd cfg.set_now_int sctp autoclose 120
... ...
@@ -288,6 +288,18 @@ new config variables:
288 288
                       1-3) to avoid "multiplying" traffic to unresponding 
289 289
                       hosts (default: 0).
290 290
                       Can be changed at runtime.
291
+  sctp_srto_initial = milliseconds - initial value of the retr. timeout,
292
+                      used in RTO calculations (default: OS specific).
293
+                      Can be changed at runtime (sctp srto_initial) but it
294
+                      will affect only new associations.
295
+  sctp_srto_max     = milliseconds - maximum value of the retransmission
296
+                      timeout (RTO) (default: OS specific).
297
+                      Can be changed at runtime (sctp srto_max) but it
298
+                      will affect only new associations.
299
+  sctp_srto_min     = milliseconds - minimum value of the retransmission
300
+                      timeout (RTO) (default: OS specific).
301
+                      Can be changed at runtime (sctp srto_min) but it 
302
+                      will affect only new associations.
291 303
   server_id = number - A configurable unique server id that can be used to
292 304
                        discriminate server instances within a cluster of
293 305
                        servers when all other information, such as IP addresses
... ...
@@ -338,6 +338,9 @@ SCTP_SOCKET_SNDBUF	"sctp_socket_sndbuf"|"sctp_socket_send_buffer"
338 338
 SCTP_AUTOCLOSE	"sctp_autoclose"
339 339
 SCTP_SEND_TTL	"sctp_send_ttl"
340 340
 SCTP_SEND_RETRIES	"sctp_send_retries"
341
+SCTP_SRTO_INITIAL	"sctp_srto_initial"
342
+SCTP_SRTO_MAX		"sctp_srto_max"
343
+SCTP_SRTO_MIN		"sctp_srto_min"
341 344
 ADVERTISED_ADDRESS	"advertised_address"
342 345
 ADVERTISED_PORT		"advertised_port"
343 346
 DISABLE_CORE		"disable_core_dump"
... ...
@@ -667,6 +670,12 @@ EAT_ABLE	[\ \t\b\r]
667 667
 										return SCTP_SEND_TTL; }
668 668
 <INITIAL>{SCTP_SEND_RETRIES}	{ count(); yylval.strval=yytext;
669 669
 										return SCTP_SEND_RETRIES; }
670
+<INITIAL>{SCTP_SRTO_INITIAL}	{ count(); yylval.strval=yytext;
671
+										return SCTP_SRTO_INITIAL; }
672
+<INITIAL>{SCTP_SRTO_MAX}	{ count(); yylval.strval=yytext;
673
+										return SCTP_SRTO_MAX; }
674
+<INITIAL>{SCTP_SRTO_MIN}	{ count(); yylval.strval=yytext;
675
+										return SCTP_SRTO_MIN; }
670 676
 <INITIAL>{SERVER_SIGNATURE}	{ count(); yylval.strval=yytext; return SERVER_SIGNATURE; }
671 677
 <INITIAL>{REPLY_TO_VIA}	{ count(); yylval.strval=yytext; return REPLY_TO_VIA; }
672 678
 <INITIAL>{ADVERTISED_ADDRESS}	{	count(); yylval.strval=yytext;
... ...
@@ -172,6 +172,12 @@
172 172
 	#define IF_STUN(x) warn("stun support not compiled in")
173 173
 #endif
174 174
 
175
+#ifdef USE_SCTP
176
+	#define IF_SCTP(x) x
177
+#else
178
+	#define IF_SCTP(x) warn("sctp support not compiled in")
179
+#endif
180
+
175 181
 
176 182
 extern int yylex();
177 183
 static void yyerror(char* s);
... ...
@@ -396,6 +402,9 @@ static void free_socket_id_lst(struct socket_id* i);
396 396
 %token SCTP_AUTOCLOSE
397 397
 %token SCTP_SEND_TTL
398 398
 %token SCTP_SEND_RETRIES
399
+%token SCTP_SRTO_INITIAL
400
+%token SCTP_SRTO_MAX
401
+%token SCTP_SRTO_MIN
399 402
 %token ADVERTISED_ADDRESS
400 403
 %token ADVERTISED_PORT
401 404
 %token DISABLE_CORE
... ...
@@ -1187,6 +1196,18 @@ assign_stm:
1187 1187
 		#endif
1188 1188
 	}
1189 1189
 	| SCTP_SEND_RETRIES EQUAL error { yyerror("number expected"); }
1190
+	| SCTP_SRTO_INITIAL EQUAL NUMBER {
1191
+			IF_SCTP(sctp_default_cfg.srto_initial=$3);
1192
+	}
1193
+	| SCTP_SRTO_INITIAL EQUAL error { yyerror("number expected"); }
1194
+	| SCTP_SRTO_MAX EQUAL NUMBER {
1195
+			IF_SCTP(sctp_default_cfg.srto_max=$3);
1196
+	}
1197
+	| SCTP_SRTO_MAX EQUAL error { yyerror("number expected"); }
1198
+	| SCTP_SRTO_MIN EQUAL NUMBER {
1199
+			IF_SCTP(sctp_default_cfg.srto_min=$3);
1200
+	}
1201
+	| SCTP_SRTO_MIN EQUAL error { yyerror("number expected"); }
1190 1202
 	| SERVER_SIGNATURE EQUAL NUMBER { server_signature=$3; }
1191 1203
 	| SERVER_SIGNATURE EQUAL error { yyerror("boolean value expected"); }
1192 1204
 	| REPLY_TO_VIA EQUAL NUMBER { reply_to_via=$3; }
... ...
@@ -613,12 +613,15 @@ static void core_sctp_options(rpc_t* rpc, void* c)
613 613
 	if (!sctp_disable){
614 614
 		sctp_options_get(&t);
615 615
 		rpc->add(c, "{", &handle);
616
-		rpc->struct_add(handle, "ddddd",
616
+		rpc->struct_add(handle, "dddddddd",
617
+			"sctp_socket_rcvbuf",	t.so_rcvbuf,
618
+			"sctp_socket_sndbuf",	t.so_sndbuf,
617 619
 			"sctp_autoclose",		t.autoclose,
618 620
 			"sctp_send_ttl",	t.send_ttl,
619 621
 			"sctp_send_retries",	t.send_retries,
620
-			"sctp_socket_rcvbuf",	t.so_rcvbuf,
621
-			"sctp_socket_sndbuf",	t.so_sndbuf
622
+			"sctp_srto_initial",	t.srto_initial,
623
+			"sctp_srto_max",		t.srto_max,
624
+			"sctp_srto_min",		t.srto_min
622 625
 		);
623 626
 	}else{
624 627
 		rpc->fault(c, 500, "sctp support disabled");
... ...
@@ -48,6 +48,9 @@ struct cfg_group_sctp sctp_default_cfg;
48 48
 
49 49
 
50 50
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val);
51
+static int set_srto_initial(void* cfg_h, str* gname, str* name, void** val);
52
+static int set_srto_max(void* cfg_h, str* gname, str* name, void** val);
53
+static int set_srto_min(void* cfg_h, str* gname, str* name, void** val);
51 54
 
52 55
 /** cfg_group_sctp description (for the config framework). */
53 56
 static cfg_def_t sctp_cfg_def[] = {
... ...
@@ -63,6 +66,13 @@ static cfg_def_t sctp_cfg_def[] = {
63 63
 		"milliseconds before aborting a send" },
64 64
 	{ "send_retries", CFG_VAR_INT| CFG_ATOMIC, 0, MAX_SCTP_SEND_RETRIES, 0, 0,
65 65
 		"re-send attempts on failure" },
66
+	{ "srto_initial", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_initial, 0,
67
+		"initial value of the retr. timeout, used in RTO calculations,"
68
+			" in msecs" },
69
+	{ "srto_max", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_max, 0,
70
+		"maximum value of the retransmission timeout (RTO), in msecs" },
71
+	{ "srto_min", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_min, 0,
72
+		"minimum value og the retransmission timeout (RTO), in msecs" },
66 73
 	{0, 0, 0, 0, 0, 0, 0}
67 74
 };
68 75
 
... ...
@@ -75,8 +85,11 @@ void* sctp_cfg; /* sctp config handle */
75 75
 void init_sctp_options()
76 76
 {
77 77
 #ifdef USE_SCTP
78
+	sctp_get_os_defaults(&sctp_default_cfg);
79
+#if 0
78 80
 	sctp_default_cfg.so_rcvbuf=0; /* do nothing, use the kernel default */
79 81
 	sctp_default_cfg.so_sndbuf=0; /* do nothing, use the kernel default */
82
+#endif
80 83
 	sctp_default_cfg.autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
81 84
 	sctp_default_cfg.send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
82 85
 	sctp_default_cfg.send_retries=DEFAULT_SCTP_SEND_RETRIES;
... ...
@@ -139,23 +152,102 @@ int sctp_register_cfg()
139 139
 
140 140
 
141 141
 
142
+#define SCTP_SET_SOCKOPT_DECLS \
143
+	int err; \
144
+	struct socket_info* si
145
+
146
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
147
+	err=0; \
148
+	for (si=sctp_listen; si; si=si->next){ \
149
+		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
150
+							sizeof((val)), (err_prefix))<0); \
151
+	} \
152
+	return -(err!=0)
153
+
154
+
155
+
142 156
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val)
143 157
 {
144 158
 #ifdef SCTP_AUTOCLOSE
145 159
 	int optval;
146
-	int err;
147
-	struct socket_info* si;
160
+	SCTP_SET_SOCKOPT_DECLS;
148 161
 	
149 162
 	optval=(int)(long)(*val);
150
-	err=0;
151
-	for (si=sctp_listen; si; si=si->next){
152
-		err+=(sctp_sockopt(si, IPPROTO_SCTP, SCTP_AUTOCLOSE, (void*)&optval,
153
-							sizeof(optval), "cfg: setting SCTP_AUTOCLOSE")<0);
154
-	}
155
-	return -(err!=0);
163
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_AUTOCLOSE, optval,
164
+							"cfg: setting SCTP_AUTOCLOSE");
156 165
 #else
157 166
 	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
158 167
 	return -1;
159 168
 #endif /* SCTP_AUTOCLOSE */
160 169
 }
170
+
171
+
172
+
173
+static int set_srto_initial(void* cfg_h, str* gname, str* name, void** val)
174
+{
175
+#ifdef SCTP_RTOINFO
176
+	struct sctp_rtoinfo rto;
177
+	SCTP_SET_SOCKOPT_DECLS;
178
+	
179
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
180
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_initial);
181
+		return 0;
182
+	}
183
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
184
+	rto.srto_assoc_id=0; /* all */
185
+	rto.srto_initial=(int)(long)(*val);
186
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
187
+							"cfg: setting SCTP_RTOINFO");
188
+#else
189
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
190
+	return -1;
191
+#endif /* SCTP_RTOINFO */
192
+}
193
+
194
+
195
+
196
+static int set_srto_max(void* cfg_h, str* gname, str* name, void** val)
197
+{
198
+#ifdef SCTP_RTOINFO
199
+	struct sctp_rtoinfo rto;
200
+	SCTP_SET_SOCKOPT_DECLS;
201
+	
202
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
203
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_max);
204
+		return 0;
205
+	}
206
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
207
+	rto.srto_assoc_id=0; /* all */
208
+	rto.srto_max=(int)(long)(*val);
209
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
210
+							"cfg: setting SCTP_RTOINFO");
211
+#else
212
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
213
+	return -1;
214
+#endif /* SCTP_RTOINFO */
215
+}
216
+
217
+
218
+
219
+static int set_srto_min(void* cfg_h, str* gname, str* name, void** val)
220
+{
221
+#ifdef SCTP_RTOINFO
222
+	struct sctp_rtoinfo rto;
223
+	SCTP_SET_SOCKOPT_DECLS;
224
+	
225
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
226
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_min);
227
+		return 0;
228
+	}
229
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
230
+	rto.srto_assoc_id=0; /* all */
231
+	rto.srto_min=(int)(long)(*val);
232
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
233
+							"cfg: setting SCTP_RTOINFO");
234
+#else
235
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
236
+	return -1;
237
+#endif /* SCTP_RTOINFO */
238
+}
239
+
161 240
 #endif /* USE_SCTP */
... ...
@@ -40,6 +40,9 @@ struct cfg_group_sctp{
40 40
 	unsigned int autoclose; /* in seconds */
41 41
 	unsigned int send_ttl; /* in milliseconds */
42 42
 	unsigned int send_retries;
43
+	unsigned int srto_initial;
44
+	unsigned int srto_max;
45
+	unsigned int srto_min;
43 46
 };
44 47
 
45 48
 extern struct cfg_group_sctp sctp_default_cfg;
... ...
@@ -51,5 +54,6 @@ void init_sctp_options();
51 51
 void sctp_options_check();
52 52
 int sctp_register_cfg();
53 53
 void sctp_options_get(struct cfg_group_sctp *s);
54
+int sctp_get_os_defaults(struct cfg_group_sctp *s);
54 55
 
55 56
 #endif /* _sctp_options_h */
... ...
@@ -65,6 +65,8 @@
65 65
 
66 66
 static atomic_t* sctp_conn_no;
67 67
 
68
+
69
+
68 70
 /* check if the underlying OS supports sctp
69 71
    returns 0 if yes, -1 on error */
70 72
 int sctp_check_support()
... ...
@@ -189,10 +191,27 @@ error:
189 189
   * @param err_prefix - if 0 no error message is printed on failure, if !=0
190 190
   *                     it will be prepended to the error message.
191 191
   * @return 0 on success, -1 on error */
192
-int sctp_sockopt(struct socket_info* si, int level, int optname, void* optval,
193
-					socklen_t optlen, char* err_prefix)
192
+int sctp_setsockopt(int s, int level, int optname, 
193
+					void* optval, socklen_t optlen, char* err_prefix)
194
+{
195
+	if (setsockopt(s, level, optname, optval, optlen) ==-1){
196
+		if (err_prefix)
197
+			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
198
+		return -1;
199
+	}
200
+	return 0;
201
+}
202
+
203
+
204
+
205
+/** get a socket option (wrapper over getsockopt).
206
+  * @param err_prefix - if 0 no error message is printed on failure, if !=0
207
+  *                     it will be prepended to the error message.
208
+  * @return 0 on success, -1 on error */
209
+int sctp_getsockopt(int s, int level, int optname, 
210
+					void* optval, socklen_t* optlen, char* err_prefix)
194 211
 {
195
-	if (setsockopt(si->socket, level, optname, optval, optlen) ==-1){
212
+	if (getsockopt(s, level, optname, optval, optlen) ==-1){
196 213
 		if (err_prefix)
197 214
 			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
198 215
 		return -1;
... ...
@@ -202,6 +221,62 @@ int sctp_sockopt(struct socket_info* si, int level, int optname, void* optval,
202 202
 
203 203
 
204 204
 
205
+/** get the os defaults for cfg options with os correspondents.
206
+ *  @param s - intialized sctp socket
207
+ *  @param cfg - filled with the os defaults
208
+ *  @return -1 on error, 0 on success
209
+ */
210
+int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
211
+{
212
+	int optval;
213
+	socklen_t optlen;
214
+	int s;
215
+#ifdef SCTP_RTOINFO
216
+	struct sctp_rtoinfo rto;
217
+#endif /* SCTP_RTOINFO */
218
+	
219
+	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
220
+	if (s==-1)
221
+		return -1;
222
+	
223
+	/* SO_RCVBUF */
224
+	optlen=sizeof(int);
225
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
226
+							&optlen, "SO_RCVBUF")==0){
227
+		/* success => hack to set the "default" values*/
228
+		#ifdef __OS_linux
229
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
230
+		#endif
231
+		cfg->so_rcvbuf=optval;
232
+	}
233
+	/* SO_SNDBUF */
234
+	optlen=sizeof(int);
235
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&optval,
236
+							&optlen, "SO_SNDBUF")==0){
237
+		/* success => hack to set the "default" values*/
238
+		#ifdef __OS_linux
239
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
240
+		#endif
241
+		cfg->so_sndbuf=optval;
242
+	}
243
+	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
244
+#ifdef SCTP_RTOINFO
245
+	optlen=sizeof(rto);
246
+	rto.srto_assoc_id=0;
247
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
248
+							&optlen, "SCTP_RTOINFO")==0){
249
+		/* success => hack to set the "default" values*/
250
+		cfg->srto_initial=rto.srto_initial;
251
+		cfg->srto_min=rto.srto_min;
252
+		cfg->srto_max=rto.srto_max;
253
+	}
254
+#endif /* SCTP_RTOINFO */
255
+	close(s);
256
+	return 0;
257
+}
258
+
259
+
260
+
205 261
 /* set common (for one to many and one to one) sctp socket options
206 262
    tries to ignore non-critical errors (it will only log them), for
207 263
    improved portability (for example older linux kernel version support
... ...
@@ -215,6 +290,9 @@ static int sctp_init_sock_opt_common(int s)
215 215
 	int saved_errno;
216 216
 	socklen_t optlen;
217 217
 	int sctp_err;
218
+#ifdef SCTP_RTOINFO
219
+	struct sctp_rtoinfo rto;
220
+#endif /* SCTP_RTOINFO */
218 221
 #ifdef __OS_linux
219 222
 	union {
220 223
 		struct sctp_event_subscribe s;
... ...
@@ -375,6 +453,23 @@ static int sctp_init_sock_opt_common(int s)
375 375
 #else
376 376
 #error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
377 377
 #endif /* SCTP_AUTOCLOSE */
378
+	/* set rtoinfo options: srto_initial, srto_min, srto_max */
379
+#ifdef SCTP_RTOINFO
380
+	memset(&rto, 0, sizeof(rto));
381
+	rto.srto_initial=cfg_get(sctp, sctp_cfg, srto_initial);
382
+	rto.srto_min=cfg_get(sctp, sctp_cfg, srto_min);
383
+	rto.srto_max=cfg_get(sctp, sctp_cfg, srto_max);
384
+	if (rto.srto_initial || rto.srto_min || rto.srto_max){
385
+		/* if at least one is non-null => we have to set it */
386
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
387
+							sizeof(rto), "setsockopt: SCTP_RTOINFO")!=0){
388
+			sctp_err++;
389
+			/* non critical, try to continue */
390
+		}
391
+	}
392
+#else
393
+#warning no sctp lib support for SCTP_RTOINFO, consider upgrading
394
+#endif /* SCTP_RTOINFO */
378 395
 	
379 396
 	memset(&es, 0, sizeof(es));
380 397
 	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
... ...
@@ -48,6 +48,6 @@ void sctp_get_info(struct sctp_gen_info* sinf);
48 48
 
49 49
 void destroy_sctp();
50 50
 
51
-int sctp_sockopt(struct socket_info* si, int level, int optname, void* optval,
52
-					socklen_t optlen, char* err_prefix);
51
+int sctp_setsockopt(int s, int level, int optname,
52
+					void* optval, socklen_t optlen, char* err_prefix);
53 53
 #endif /* _sctp_server_h */