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 670
 										return SCTP_SEND_TTL; }
668 671
 <INITIAL>{SCTP_SEND_RETRIES}	{ count(); yylval.strval=yytext;
669 672
 										return SCTP_SEND_RETRIES; }
673
+<INITIAL>{SCTP_SRTO_INITIAL}	{ count(); yylval.strval=yytext;
674
+										return SCTP_SRTO_INITIAL; }
675
+<INITIAL>{SCTP_SRTO_MAX}	{ count(); yylval.strval=yytext;
676
+										return SCTP_SRTO_MAX; }
677
+<INITIAL>{SCTP_SRTO_MIN}	{ count(); yylval.strval=yytext;
678
+										return SCTP_SRTO_MIN; }
670 679
 <INITIAL>{SERVER_SIGNATURE}	{ count(); yylval.strval=yytext; return SERVER_SIGNATURE; }
671 680
 <INITIAL>{REPLY_TO_VIA}	{ count(); yylval.strval=yytext; return REPLY_TO_VIA; }
672 681
 <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 402
 %token SCTP_AUTOCLOSE
397 403
 %token SCTP_SEND_TTL
398 404
 %token SCTP_SEND_RETRIES
405
+%token SCTP_SRTO_INITIAL
406
+%token SCTP_SRTO_MAX
407
+%token SCTP_SRTO_MIN
399 408
 %token ADVERTISED_ADDRESS
400 409
 %token ADVERTISED_PORT
401 410
 %token DISABLE_CORE
... ...
@@ -1187,6 +1196,18 @@ assign_stm:
1187 1196
 		#endif
1188 1197
 	}
1189 1198
 	| SCTP_SEND_RETRIES EQUAL error { yyerror("number expected"); }
1199
+	| SCTP_SRTO_INITIAL EQUAL NUMBER {
1200
+			IF_SCTP(sctp_default_cfg.srto_initial=$3);
1201
+	}
1202
+	| SCTP_SRTO_INITIAL EQUAL error { yyerror("number expected"); }
1203
+	| SCTP_SRTO_MAX EQUAL NUMBER {
1204
+			IF_SCTP(sctp_default_cfg.srto_max=$3);
1205
+	}
1206
+	| SCTP_SRTO_MAX EQUAL error { yyerror("number expected"); }
1207
+	| SCTP_SRTO_MIN EQUAL NUMBER {
1208
+			IF_SCTP(sctp_default_cfg.srto_min=$3);
1209
+	}
1210
+	| SCTP_SRTO_MIN EQUAL error { yyerror("number expected"); }
1190 1211
 	| SERVER_SIGNATURE EQUAL NUMBER { server_signature=$3; }
1191 1212
 	| SERVER_SIGNATURE EQUAL error { yyerror("boolean value expected"); }
1192 1213
 	| 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 66
 		"milliseconds before aborting a send" },
64 67
 	{ "send_retries", CFG_VAR_INT| CFG_ATOMIC, 0, MAX_SCTP_SEND_RETRIES, 0, 0,
65 68
 		"re-send attempts on failure" },
69
+	{ "srto_initial", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_initial, 0,
70
+		"initial value of the retr. timeout, used in RTO calculations,"
71
+			" in msecs" },
72
+	{ "srto_max", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_max, 0,
73
+		"maximum value of the retransmission timeout (RTO), in msecs" },
74
+	{ "srto_min", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_min, 0,
75
+		"minimum value og the retransmission timeout (RTO), in msecs" },
66 76
 	{0, 0, 0, 0, 0, 0, 0}
67 77
 };
68 78
 
... ...
@@ -75,8 +85,11 @@ void* sctp_cfg; /* sctp config handle */
75 85
 void init_sctp_options()
76 86
 {
77 87
 #ifdef USE_SCTP
88
+	sctp_get_os_defaults(&sctp_default_cfg);
89
+#if 0
78 90
 	sctp_default_cfg.so_rcvbuf=0; /* do nothing, use the kernel default */
79 91
 	sctp_default_cfg.so_sndbuf=0; /* do nothing, use the kernel default */
92
+#endif
80 93
 	sctp_default_cfg.autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
81 94
 	sctp_default_cfg.send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
82 95
 	sctp_default_cfg.send_retries=DEFAULT_SCTP_SEND_RETRIES;
... ...
@@ -139,23 +152,102 @@ int sctp_register_cfg()
139 152
 
140 153
 
141 154
 
155
+#define SCTP_SET_SOCKOPT_DECLS \
156
+	int err; \
157
+	struct socket_info* si
158
+
159
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
160
+	err=0; \
161
+	for (si=sctp_listen; si; si=si->next){ \
162
+		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
163
+							sizeof((val)), (err_prefix))<0); \
164
+	} \
165
+	return -(err!=0)
166
+
167
+
168
+
142 169
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val)
143 170
 {
144 171
 #ifdef SCTP_AUTOCLOSE
145 172
 	int optval;
146
-	int err;
147
-	struct socket_info* si;
173
+	SCTP_SET_SOCKOPT_DECLS;
148 174
 	
149 175
 	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);
176
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_AUTOCLOSE, optval,
177
+							"cfg: setting SCTP_AUTOCLOSE");
156 178
 #else
157 179
 	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
158 180
 	return -1;
159 181
 #endif /* SCTP_AUTOCLOSE */
160 182
 }
183
+
184
+
185
+
186
+static int set_srto_initial(void* cfg_h, str* gname, str* name, void** val)
187
+{
188
+#ifdef SCTP_RTOINFO
189
+	struct sctp_rtoinfo rto;
190
+	SCTP_SET_SOCKOPT_DECLS;
191
+	
192
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
193
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_initial);
194
+		return 0;
195
+	}
196
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
197
+	rto.srto_assoc_id=0; /* all */
198
+	rto.srto_initial=(int)(long)(*val);
199
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
200
+							"cfg: setting SCTP_RTOINFO");
201
+#else
202
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
203
+	return -1;
204
+#endif /* SCTP_RTOINFO */
205
+}
206
+
207
+
208
+
209
+static int set_srto_max(void* cfg_h, str* gname, str* name, void** val)
210
+{
211
+#ifdef SCTP_RTOINFO
212
+	struct sctp_rtoinfo rto;
213
+	SCTP_SET_SOCKOPT_DECLS;
214
+	
215
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
216
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_max);
217
+		return 0;
218
+	}
219
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
220
+	rto.srto_assoc_id=0; /* all */
221
+	rto.srto_max=(int)(long)(*val);
222
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
223
+							"cfg: setting SCTP_RTOINFO");
224
+#else
225
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
226
+	return -1;
227
+#endif /* SCTP_RTOINFO */
228
+}
229
+
230
+
231
+
232
+static int set_srto_min(void* cfg_h, str* gname, str* name, void** val)
233
+{
234
+#ifdef SCTP_RTOINFO
235
+	struct sctp_rtoinfo rto;
236
+	SCTP_SET_SOCKOPT_DECLS;
237
+	
238
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
239
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_min);
240
+		return 0;
241
+	}
242
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
243
+	rto.srto_assoc_id=0; /* all */
244
+	rto.srto_min=(int)(long)(*val);
245
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
246
+							"cfg: setting SCTP_RTOINFO");
247
+#else
248
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
249
+	return -1;
250
+#endif /* SCTP_RTOINFO */
251
+}
252
+
161 253
 #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 54
 void sctp_options_check();
52 55
 int sctp_register_cfg();
53 56
 void sctp_options_get(struct cfg_group_sctp *s);
57
+int sctp_get_os_defaults(struct cfg_group_sctp *s);
54 58
 
55 59
 #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 191
   * @param err_prefix - if 0 no error message is printed on failure, if !=0
190 192
   *                     it will be prepended to the error message.
191 193
   * @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)
194
+int sctp_setsockopt(int s, int level, int optname, 
195
+					void* optval, socklen_t optlen, char* err_prefix)
196
+{
197
+	if (setsockopt(s, level, optname, optval, optlen) ==-1){
198
+		if (err_prefix)
199
+			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
200
+		return -1;
201
+	}
202
+	return 0;
203
+}
204
+
205
+
206
+
207
+/** get a socket option (wrapper over getsockopt).
208
+  * @param err_prefix - if 0 no error message is printed on failure, if !=0
209
+  *                     it will be prepended to the error message.
210
+  * @return 0 on success, -1 on error */
211
+int sctp_getsockopt(int s, int level, int optname, 
212
+					void* optval, socklen_t* optlen, char* err_prefix)
194 213
 {
195
-	if (setsockopt(si->socket, level, optname, optval, optlen) ==-1){
214
+	if (getsockopt(s, level, optname, optval, optlen) ==-1){
196 215
 		if (err_prefix)
197 216
 			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
198 217
 		return -1;
... ...
@@ -202,6 +221,62 @@ int sctp_sockopt(struct socket_info* si, int level, int optname, void* optval,
202 221
 
203 222
 
204 223
 
224
+/** get the os defaults for cfg options with os correspondents.
225
+ *  @param s - intialized sctp socket
226
+ *  @param cfg - filled with the os defaults
227
+ *  @return -1 on error, 0 on success
228
+ */
229
+int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
230
+{
231
+	int optval;
232
+	socklen_t optlen;
233
+	int s;
234
+#ifdef SCTP_RTOINFO
235
+	struct sctp_rtoinfo rto;
236
+#endif /* SCTP_RTOINFO */
237
+	
238
+	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
239
+	if (s==-1)
240
+		return -1;
241
+	
242
+	/* SO_RCVBUF */
243
+	optlen=sizeof(int);
244
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
245
+							&optlen, "SO_RCVBUF")==0){
246
+		/* success => hack to set the "default" values*/
247
+		#ifdef __OS_linux
248
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
249
+		#endif
250
+		cfg->so_rcvbuf=optval;
251
+	}
252
+	/* SO_SNDBUF */
253
+	optlen=sizeof(int);
254
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&optval,
255
+							&optlen, "SO_SNDBUF")==0){
256
+		/* success => hack to set the "default" values*/
257
+		#ifdef __OS_linux
258
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
259
+		#endif
260
+		cfg->so_sndbuf=optval;
261
+	}
262
+	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
263
+#ifdef SCTP_RTOINFO
264
+	optlen=sizeof(rto);
265
+	rto.srto_assoc_id=0;
266
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
267
+							&optlen, "SCTP_RTOINFO")==0){
268
+		/* success => hack to set the "default" values*/
269
+		cfg->srto_initial=rto.srto_initial;
270
+		cfg->srto_min=rto.srto_min;
271
+		cfg->srto_max=rto.srto_max;
272
+	}
273
+#endif /* SCTP_RTOINFO */
274
+	close(s);
275
+	return 0;
276
+}
277
+
278
+
279
+
205 280
 /* set common (for one to many and one to one) sctp socket options
206 281
    tries to ignore non-critical errors (it will only log them), for
207 282
    improved portability (for example older linux kernel version support
... ...
@@ -215,6 +290,9 @@ static int sctp_init_sock_opt_common(int s)
215 290
 	int saved_errno;
216 291
 	socklen_t optlen;
217 292
 	int sctp_err;
293
+#ifdef SCTP_RTOINFO
294
+	struct sctp_rtoinfo rto;
295
+#endif /* SCTP_RTOINFO */
218 296
 #ifdef __OS_linux
219 297
 	union {
220 298
 		struct sctp_event_subscribe s;
... ...
@@ -375,6 +453,23 @@ static int sctp_init_sock_opt_common(int s)
375 453
 #else
376 454
 #error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
377 455
 #endif /* SCTP_AUTOCLOSE */
456
+	/* set rtoinfo options: srto_initial, srto_min, srto_max */
457
+#ifdef SCTP_RTOINFO
458
+	memset(&rto, 0, sizeof(rto));
459
+	rto.srto_initial=cfg_get(sctp, sctp_cfg, srto_initial);
460
+	rto.srto_min=cfg_get(sctp, sctp_cfg, srto_min);
461
+	rto.srto_max=cfg_get(sctp, sctp_cfg, srto_max);
462
+	if (rto.srto_initial || rto.srto_min || rto.srto_max){
463
+		/* if at least one is non-null => we have to set it */
464
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
465
+							sizeof(rto), "setsockopt: SCTP_RTOINFO")!=0){
466
+			sctp_err++;
467
+			/* non critical, try to continue */
468
+		}
469
+	}
470
+#else
471
+#warning no sctp lib support for SCTP_RTOINFO, consider upgrading
472
+#endif /* SCTP_RTOINFO */
378 473
 	
379 474
 	memset(&es, 0, sizeof(es));
380 475
 	/* 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 */