2
0
Эх сурвалжийг харах

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 16 жил өмнө
parent
commit
b73d58cf3d
8 өөрчлөгдсөн 253 нэмэгдсэн , 17 устгасан
  1. 13 1
      NEWS
  2. 9 0
      cfg.lex
  3. 21 0
      cfg.y
  4. 6 3
      core_cmd.c
  5. 100 8
      sctp_options.c
  6. 4 0
      sctp_options.h
  7. 98 3
      sctp_server.c
  8. 2 2
      sctp_server.h

+ 13 - 1
NEWS

@@ -271,7 +271,7 @@ new config variables:
   sctp_socket_rcvbuf = number - size for the sctp socket receive buffer
   sctp_socket_sndbuf = number - size for the sctp socket send buffer
   sctp_autoclose = seconds - number of seconds before autoclosing an idle
-                   assocation (default: 180 s).
+                   association (default: 180 s).
                    Can be changed at runtime, but it will affect only new
                    associations. E.g.:
                    $ sercmd cfg.set_now_int sctp autoclose 120
@@ -288,6 +288,18 @@ new config variables:
                       1-3) to avoid "multiplying" traffic to unresponding 
                       hosts (default: 0).
                       Can be changed at runtime.
+  sctp_srto_initial = milliseconds - initial value of the retr. timeout,
+                      used in RTO calculations (default: OS specific).
+                      Can be changed at runtime (sctp srto_initial) but it
+                      will affect only new associations.
+  sctp_srto_max     = milliseconds - maximum value of the retransmission
+                      timeout (RTO) (default: OS specific).
+                      Can be changed at runtime (sctp srto_max) but it
+                      will affect only new associations.
+  sctp_srto_min     = milliseconds - minimum value of the retransmission
+                      timeout (RTO) (default: OS specific).
+                      Can be changed at runtime (sctp srto_min) but it 
+                      will affect only new associations.
   server_id = number - A configurable unique server id that can be used to
                        discriminate server instances within a cluster of
                        servers when all other information, such as IP addresses

+ 9 - 0
cfg.lex

@@ -338,6 +338,9 @@ SCTP_SOCKET_SNDBUF	"sctp_socket_sndbuf"|"sctp_socket_send_buffer"
 SCTP_AUTOCLOSE	"sctp_autoclose"
 SCTP_SEND_TTL	"sctp_send_ttl"
 SCTP_SEND_RETRIES	"sctp_send_retries"
+SCTP_SRTO_INITIAL	"sctp_srto_initial"
+SCTP_SRTO_MAX		"sctp_srto_max"
+SCTP_SRTO_MIN		"sctp_srto_min"
 ADVERTISED_ADDRESS	"advertised_address"
 ADVERTISED_PORT		"advertised_port"
 DISABLE_CORE		"disable_core_dump"
@@ -667,6 +670,12 @@ EAT_ABLE	[\ \t\b\r]
 										return SCTP_SEND_TTL; }
 <INITIAL>{SCTP_SEND_RETRIES}	{ count(); yylval.strval=yytext;
 										return SCTP_SEND_RETRIES; }
+<INITIAL>{SCTP_SRTO_INITIAL}	{ count(); yylval.strval=yytext;
+										return SCTP_SRTO_INITIAL; }
+<INITIAL>{SCTP_SRTO_MAX}	{ count(); yylval.strval=yytext;
+										return SCTP_SRTO_MAX; }
+<INITIAL>{SCTP_SRTO_MIN}	{ count(); yylval.strval=yytext;
+										return SCTP_SRTO_MIN; }
 <INITIAL>{SERVER_SIGNATURE}	{ count(); yylval.strval=yytext; return SERVER_SIGNATURE; }
 <INITIAL>{REPLY_TO_VIA}	{ count(); yylval.strval=yytext; return REPLY_TO_VIA; }
 <INITIAL>{ADVERTISED_ADDRESS}	{	count(); yylval.strval=yytext;

+ 21 - 0
cfg.y

@@ -172,6 +172,12 @@
 	#define IF_STUN(x) warn("stun support not compiled in")
 #endif
 
+#ifdef USE_SCTP
+	#define IF_SCTP(x) x
+#else
+	#define IF_SCTP(x) warn("sctp support not compiled in")
+#endif
+
 
 extern int yylex();
 static void yyerror(char* s);
@@ -396,6 +402,9 @@ static void free_socket_id_lst(struct socket_id* i);
 %token SCTP_AUTOCLOSE
 %token SCTP_SEND_TTL
 %token SCTP_SEND_RETRIES
+%token SCTP_SRTO_INITIAL
+%token SCTP_SRTO_MAX
+%token SCTP_SRTO_MIN
 %token ADVERTISED_ADDRESS
 %token ADVERTISED_PORT
 %token DISABLE_CORE
@@ -1187,6 +1196,18 @@ assign_stm:
 		#endif
 	}
 	| SCTP_SEND_RETRIES EQUAL error { yyerror("number expected"); }
+	| SCTP_SRTO_INITIAL EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.srto_initial=$3);
+	}
+	| SCTP_SRTO_INITIAL EQUAL error { yyerror("number expected"); }
+	| SCTP_SRTO_MAX EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.srto_max=$3);
+	}
+	| SCTP_SRTO_MAX EQUAL error { yyerror("number expected"); }
+	| SCTP_SRTO_MIN EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.srto_min=$3);
+	}
+	| SCTP_SRTO_MIN EQUAL error { yyerror("number expected"); }
 	| SERVER_SIGNATURE EQUAL NUMBER { server_signature=$3; }
 	| SERVER_SIGNATURE EQUAL error { yyerror("boolean value expected"); }
 	| REPLY_TO_VIA EQUAL NUMBER { reply_to_via=$3; }

+ 6 - 3
core_cmd.c

@@ -613,12 +613,15 @@ static void core_sctp_options(rpc_t* rpc, void* c)
 	if (!sctp_disable){
 		sctp_options_get(&t);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "ddddd",
+		rpc->struct_add(handle, "dddddddd",
+			"sctp_socket_rcvbuf",	t.so_rcvbuf,
+			"sctp_socket_sndbuf",	t.so_sndbuf,
 			"sctp_autoclose",		t.autoclose,
 			"sctp_send_ttl",	t.send_ttl,
 			"sctp_send_retries",	t.send_retries,
-			"sctp_socket_rcvbuf",	t.so_rcvbuf,
-			"sctp_socket_sndbuf",	t.so_sndbuf
+			"sctp_srto_initial",	t.srto_initial,
+			"sctp_srto_max",		t.srto_max,
+			"sctp_srto_min",		t.srto_min
 		);
 	}else{
 		rpc->fault(c, 500, "sctp support disabled");

+ 100 - 8
sctp_options.c

@@ -48,6 +48,9 @@ struct cfg_group_sctp sctp_default_cfg;
 
 
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val);
+static int set_srto_initial(void* cfg_h, str* gname, str* name, void** val);
+static int set_srto_max(void* cfg_h, str* gname, str* name, void** val);
+static int set_srto_min(void* cfg_h, str* gname, str* name, void** val);
 
 /** cfg_group_sctp description (for the config framework). */
 static cfg_def_t sctp_cfg_def[] = {
@@ -63,6 +66,13 @@ static cfg_def_t sctp_cfg_def[] = {
 		"milliseconds before aborting a send" },
 	{ "send_retries", CFG_VAR_INT| CFG_ATOMIC, 0, MAX_SCTP_SEND_RETRIES, 0, 0,
 		"re-send attempts on failure" },
+	{ "srto_initial", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_initial, 0,
+		"initial value of the retr. timeout, used in RTO calculations,"
+			" in msecs" },
+	{ "srto_max", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_max, 0,
+		"maximum value of the retransmission timeout (RTO), in msecs" },
+	{ "srto_min", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_min, 0,
+		"minimum value og the retransmission timeout (RTO), in msecs" },
 	{0, 0, 0, 0, 0, 0, 0}
 };
 
@@ -75,8 +85,11 @@ void* sctp_cfg; /* sctp config handle */
 void init_sctp_options()
 {
 #ifdef USE_SCTP
+	sctp_get_os_defaults(&sctp_default_cfg);
+#if 0
 	sctp_default_cfg.so_rcvbuf=0; /* do nothing, use the kernel default */
 	sctp_default_cfg.so_sndbuf=0; /* do nothing, use the kernel default */
+#endif
 	sctp_default_cfg.autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
 	sctp_default_cfg.send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
 	sctp_default_cfg.send_retries=DEFAULT_SCTP_SEND_RETRIES;
@@ -139,23 +152,102 @@ int sctp_register_cfg()
 
 
 
+#define SCTP_SET_SOCKOPT_DECLS \
+	int err; \
+	struct socket_info* si
+
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
+	err=0; \
+	for (si=sctp_listen; si; si=si->next){ \
+		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
+							sizeof((val)), (err_prefix))<0); \
+	} \
+	return -(err!=0)
+
+
+
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val)
 {
 #ifdef SCTP_AUTOCLOSE
 	int optval;
-	int err;
-	struct socket_info* si;
+	SCTP_SET_SOCKOPT_DECLS;
 	
 	optval=(int)(long)(*val);
-	err=0;
-	for (si=sctp_listen; si; si=si->next){
-		err+=(sctp_sockopt(si, IPPROTO_SCTP, SCTP_AUTOCLOSE, (void*)&optval,
-							sizeof(optval), "cfg: setting SCTP_AUTOCLOSE")<0);
-	}
-	return -(err!=0);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_AUTOCLOSE, optval,
+							"cfg: setting SCTP_AUTOCLOSE");
 #else
 	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
 	return -1;
 #endif /* SCTP_AUTOCLOSE */
 }
+
+
+
+static int set_srto_initial(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_initial);
+		return 0;
+	}
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_initial=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+							"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
+}
+
+
+
+static int set_srto_max(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_max);
+		return 0;
+	}
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_max=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+							"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
+}
+
+
+
+static int set_srto_min(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_min);
+		return 0;
+	}
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_min=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+							"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
+}
+
 #endif /* USE_SCTP */

+ 4 - 0
sctp_options.h

@@ -40,6 +40,9 @@ struct cfg_group_sctp{
 	unsigned int autoclose; /* in seconds */
 	unsigned int send_ttl; /* in milliseconds */
 	unsigned int send_retries;
+	unsigned int srto_initial;
+	unsigned int srto_max;
+	unsigned int srto_min;
 };
 
 extern struct cfg_group_sctp sctp_default_cfg;
@@ -51,5 +54,6 @@ void init_sctp_options();
 void sctp_options_check();
 int sctp_register_cfg();
 void sctp_options_get(struct cfg_group_sctp *s);
+int sctp_get_os_defaults(struct cfg_group_sctp *s);
 
 #endif /* _sctp_options_h */

+ 98 - 3
sctp_server.c

@@ -65,6 +65,8 @@
 
 static atomic_t* sctp_conn_no;
 
+
+
 /* check if the underlying OS supports sctp
    returns 0 if yes, -1 on error */
 int sctp_check_support()
@@ -189,10 +191,27 @@ error:
   * @param err_prefix - if 0 no error message is printed on failure, if !=0
   *                     it will be prepended to the error message.
   * @return 0 on success, -1 on error */
-int sctp_sockopt(struct socket_info* si, int level, int optname, void* optval,
-					socklen_t optlen, char* err_prefix)
+int sctp_setsockopt(int s, int level, int optname, 
+					void* optval, socklen_t optlen, char* err_prefix)
+{
+	if (setsockopt(s, level, optname, optval, optlen) ==-1){
+		if (err_prefix)
+			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
+		return -1;
+	}
+	return 0;
+}
+
+
+
+/** get a socket option (wrapper over getsockopt).
+  * @param err_prefix - if 0 no error message is printed on failure, if !=0
+  *                     it will be prepended to the error message.
+  * @return 0 on success, -1 on error */
+int sctp_getsockopt(int s, int level, int optname, 
+					void* optval, socklen_t* optlen, char* err_prefix)
 {
-	if (setsockopt(si->socket, level, optname, optval, optlen) ==-1){
+	if (getsockopt(s, level, optname, optval, optlen) ==-1){
 		if (err_prefix)
 			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
 		return -1;
@@ -202,6 +221,62 @@ int sctp_sockopt(struct socket_info* si, int level, int optname, void* optval,
 
 
 
+/** get the os defaults for cfg options with os correspondents.
+ *  @param s - intialized sctp socket
+ *  @param cfg - filled with the os defaults
+ *  @return -1 on error, 0 on success
+ */
+int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
+{
+	int optval;
+	socklen_t optlen;
+	int s;
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+#endif /* SCTP_RTOINFO */
+	
+	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+	if (s==-1)
+		return -1;
+	
+	/* SO_RCVBUF */
+	optlen=sizeof(int);
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
+							&optlen, "SO_RCVBUF")==0){
+		/* success => hack to set the "default" values*/
+		#ifdef __OS_linux
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
+		#endif
+		cfg->so_rcvbuf=optval;
+	}
+	/* SO_SNDBUF */
+	optlen=sizeof(int);
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&optval,
+							&optlen, "SO_SNDBUF")==0){
+		/* success => hack to set the "default" values*/
+		#ifdef __OS_linux
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
+		#endif
+		cfg->so_sndbuf=optval;
+	}
+	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
+#ifdef SCTP_RTOINFO
+	optlen=sizeof(rto);
+	rto.srto_assoc_id=0;
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
+							&optlen, "SCTP_RTOINFO")==0){
+		/* success => hack to set the "default" values*/
+		cfg->srto_initial=rto.srto_initial;
+		cfg->srto_min=rto.srto_min;
+		cfg->srto_max=rto.srto_max;
+	}
+#endif /* SCTP_RTOINFO */
+	close(s);
+	return 0;
+}
+
+
+
 /* set common (for one to many and one to one) sctp socket options
    tries to ignore non-critical errors (it will only log them), for
    improved portability (for example older linux kernel version support
@@ -215,6 +290,9 @@ static int sctp_init_sock_opt_common(int s)
 	int saved_errno;
 	socklen_t optlen;
 	int sctp_err;
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+#endif /* SCTP_RTOINFO */
 #ifdef __OS_linux
 	union {
 		struct sctp_event_subscribe s;
@@ -375,6 +453,23 @@ static int sctp_init_sock_opt_common(int s)
 #else
 #error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
 #endif /* SCTP_AUTOCLOSE */
+	/* set rtoinfo options: srto_initial, srto_min, srto_max */
+#ifdef SCTP_RTOINFO
+	memset(&rto, 0, sizeof(rto));
+	rto.srto_initial=cfg_get(sctp, sctp_cfg, srto_initial);
+	rto.srto_min=cfg_get(sctp, sctp_cfg, srto_min);
+	rto.srto_max=cfg_get(sctp, sctp_cfg, srto_max);
+	if (rto.srto_initial || rto.srto_min || rto.srto_max){
+		/* if at least one is non-null => we have to set it */
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
+							sizeof(rto), "setsockopt: SCTP_RTOINFO")!=0){
+			sctp_err++;
+			/* non critical, try to continue */
+		}
+	}
+#else
+#warning no sctp lib support for SCTP_RTOINFO, consider upgrading
+#endif /* SCTP_RTOINFO */
 	
 	memset(&es, 0, sizeof(es));
 	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message

+ 2 - 2
sctp_server.h

@@ -48,6 +48,6 @@ void sctp_get_info(struct sctp_gen_info* sinf);
 
 void destroy_sctp();
 
-int sctp_sockopt(struct socket_info* si, int level, int optname, void* optval,
-					socklen_t optlen, char* err_prefix);
+int sctp_setsockopt(int s, int level, int optname,
+					void* optval, socklen_t optlen, char* err_prefix);
 #endif /* _sctp_server_h */