aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/associola.c
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2012-07-21 03:56:07 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-22 15:13:46 -0400
commit5aa93bcf66f4af094d6f11096e81d5501a0b4ba5 (patch)
tree7bcf045fcae31a7e367e7eb1e0568b3702a25018 /net/sctp/associola.c
parente3906486f616da7cc086a3ba06c0df4e5a48b4ab (diff)
sctp: Implement quick failover draft from tsvwg
I've seen several attempts recently made to do quick failover of sctp transports by reducing various retransmit timers and counters. While its possible to implement a faster failover on multihomed sctp associations, its not particularly robust, in that it can lead to unneeded retransmits, as well as false connection failures due to intermittent latency on a network. Instead, lets implement the new ietf quick failover draft found here: http://tools.ietf.org/html/draft-nishida-tsvwg-sctp-failover-05 This will let the sctp stack identify transports that have had a small number of errors, and avoid using them quickly until their reliability can be re-established. I've tested this out on two virt guests connected via multiple isolated virt networks and believe its in compliance with the above draft and works well. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> CC: Vlad Yasevich <vyasevich@gmail.com> CC: Sridhar Samudrala <sri@us.ibm.com> CC: "David S. Miller" <davem@davemloft.net> CC: linux-sctp@vger.kernel.org CC: joe@perches.com Acked-by: Vlad Yasevich <vyasevich@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/associola.c')
-rw-r--r--net/sctp/associola.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 8cf348e62e74..ebaef3ed6065 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -124,6 +124,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
124 * socket values. 124 * socket values.
125 */ 125 */
126 asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt; 126 asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt;
127 asoc->pf_retrans = sctp_pf_retrans;
128
127 asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial); 129 asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial);
128 asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max); 130 asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max);
129 asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min); 131 asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min);
@@ -686,6 +688,9 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
686 /* Set the path max_retrans. */ 688 /* Set the path max_retrans. */
687 peer->pathmaxrxt = asoc->pathmaxrxt; 689 peer->pathmaxrxt = asoc->pathmaxrxt;
688 690
691 /* And the partial failure retrnas threshold */
692 peer->pf_retrans = asoc->pf_retrans;
693
689 /* Initialize the peer's SACK delay timeout based on the 694 /* Initialize the peer's SACK delay timeout based on the
690 * association configured value. 695 * association configured value.
691 */ 696 */
@@ -841,6 +846,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
841 struct sctp_ulpevent *event; 846 struct sctp_ulpevent *event;
842 struct sockaddr_storage addr; 847 struct sockaddr_storage addr;
843 int spc_state = 0; 848 int spc_state = 0;
849 bool ulp_notify = true;
844 850
845 /* Record the transition on the transport. */ 851 /* Record the transition on the transport. */
846 switch (command) { 852 switch (command) {
@@ -854,6 +860,14 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
854 spc_state = SCTP_ADDR_CONFIRMED; 860 spc_state = SCTP_ADDR_CONFIRMED;
855 else 861 else
856 spc_state = SCTP_ADDR_AVAILABLE; 862 spc_state = SCTP_ADDR_AVAILABLE;
863 /* Don't inform ULP about transition from PF to
864 * active state and set cwnd to 1, see SCTP
865 * Quick failover draft section 5.1, point 5
866 */
867 if (transport->state == SCTP_PF) {
868 ulp_notify = false;
869 transport->cwnd = 1;
870 }
857 transport->state = SCTP_ACTIVE; 871 transport->state = SCTP_ACTIVE;
858 break; 872 break;
859 873
@@ -872,6 +886,11 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
872 spc_state = SCTP_ADDR_UNREACHABLE; 886 spc_state = SCTP_ADDR_UNREACHABLE;
873 break; 887 break;
874 888
889 case SCTP_TRANSPORT_PF:
890 transport->state = SCTP_PF;
891 ulp_notify = false;
892 break;
893
875 default: 894 default:
876 return; 895 return;
877 } 896 }
@@ -879,12 +898,15 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
879 /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the 898 /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
880 * user. 899 * user.
881 */ 900 */
882 memset(&addr, 0, sizeof(struct sockaddr_storage)); 901 if (ulp_notify) {
883 memcpy(&addr, &transport->ipaddr, transport->af_specific->sockaddr_len); 902 memset(&addr, 0, sizeof(struct sockaddr_storage));
884 event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, 903 memcpy(&addr, &transport->ipaddr,
885 0, spc_state, error, GFP_ATOMIC); 904 transport->af_specific->sockaddr_len);
886 if (event) 905 event = sctp_ulpevent_make_peer_addr_change(asoc, &addr,
887 sctp_ulpq_tail_event(&asoc->ulpq, event); 906 0, spc_state, error, GFP_ATOMIC);
907 if (event)
908 sctp_ulpq_tail_event(&asoc->ulpq, event);
909 }
888 910
889 /* Select new active and retran paths. */ 911 /* Select new active and retran paths. */
890 912
@@ -900,7 +922,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
900 transports) { 922 transports) {
901 923
902 if ((t->state == SCTP_INACTIVE) || 924 if ((t->state == SCTP_INACTIVE) ||
903 (t->state == SCTP_UNCONFIRMED)) 925 (t->state == SCTP_UNCONFIRMED) ||
926 (t->state == SCTP_PF))
904 continue; 927 continue;
905 if (!first || t->last_time_heard > first->last_time_heard) { 928 if (!first || t->last_time_heard > first->last_time_heard) {
906 second = first; 929 second = first;