diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2014-06-11 12:19:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-11 15:23:17 -0400 |
commit | b82e8f31acc7d799638692e65ff017f3e1b6a43d (patch) | |
tree | 5dfe890048406a67d58ecead0e966a3954c85732 /net/sctp/associola.c | |
parent | 67cb9366ff5f99868100198efba5ca88aaa6ad25 (diff) |
net: sctp: refactor active path selection
This patch just refactors and moves the code for the active
path selection into its own helper function outside of
sctp_assoc_control_transport() which is already big enough.
No functional changes here.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/associola.c')
-rw-r--r-- | net/sctp/associola.c | 120 |
1 files changed, 61 insertions, 59 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 39579c3e0d14..9f1cc6f1535d 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <net/sctp/sm.h> | 55 | #include <net/sctp/sm.h> |
56 | 56 | ||
57 | /* Forward declarations for internal functions. */ | 57 | /* Forward declarations for internal functions. */ |
58 | static void sctp_select_active_and_retran_path(struct sctp_association *asoc); | ||
58 | static void sctp_assoc_bh_rcv(struct work_struct *work); | 59 | static void sctp_assoc_bh_rcv(struct work_struct *work); |
59 | static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc); | 60 | static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc); |
60 | static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc); | 61 | static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc); |
@@ -774,9 +775,6 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, | |||
774 | sctp_transport_cmd_t command, | 775 | sctp_transport_cmd_t command, |
775 | sctp_sn_error_t error) | 776 | sctp_sn_error_t error) |
776 | { | 777 | { |
777 | struct sctp_transport *t = NULL; | ||
778 | struct sctp_transport *first; | ||
779 | struct sctp_transport *second; | ||
780 | struct sctp_ulpevent *event; | 778 | struct sctp_ulpevent *event; |
781 | struct sockaddr_storage addr; | 779 | struct sockaddr_storage addr; |
782 | int spc_state = 0; | 780 | int spc_state = 0; |
@@ -829,13 +827,14 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, | |||
829 | return; | 827 | return; |
830 | } | 828 | } |
831 | 829 | ||
832 | /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the | 830 | /* Generate and send a SCTP_PEER_ADDR_CHANGE notification |
833 | * user. | 831 | * to the user. |
834 | */ | 832 | */ |
835 | if (ulp_notify) { | 833 | if (ulp_notify) { |
836 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | 834 | memset(&addr, 0, sizeof(struct sockaddr_storage)); |
837 | memcpy(&addr, &transport->ipaddr, | 835 | memcpy(&addr, &transport->ipaddr, |
838 | transport->af_specific->sockaddr_len); | 836 | transport->af_specific->sockaddr_len); |
837 | |||
839 | event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, | 838 | event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, |
840 | 0, spc_state, error, GFP_ATOMIC); | 839 | 0, spc_state, error, GFP_ATOMIC); |
841 | if (event) | 840 | if (event) |
@@ -843,60 +842,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, | |||
843 | } | 842 | } |
844 | 843 | ||
845 | /* Select new active and retran paths. */ | 844 | /* Select new active and retran paths. */ |
846 | 845 | sctp_select_active_and_retran_path(asoc); | |
847 | /* Look for the two most recently used active transports. | ||
848 | * | ||
849 | * This code produces the wrong ordering whenever jiffies | ||
850 | * rolls over, but we still get usable transports, so we don't | ||
851 | * worry about it. | ||
852 | */ | ||
853 | first = NULL; second = NULL; | ||
854 | |||
855 | list_for_each_entry(t, &asoc->peer.transport_addr_list, | ||
856 | transports) { | ||
857 | |||
858 | if ((t->state == SCTP_INACTIVE) || | ||
859 | (t->state == SCTP_UNCONFIRMED) || | ||
860 | (t->state == SCTP_PF)) | ||
861 | continue; | ||
862 | if (!first || t->last_time_heard > first->last_time_heard) { | ||
863 | second = first; | ||
864 | first = t; | ||
865 | } else if (!second || | ||
866 | t->last_time_heard > second->last_time_heard) | ||
867 | second = t; | ||
868 | } | ||
869 | |||
870 | /* RFC 2960 6.4 Multi-Homed SCTP Endpoints | ||
871 | * | ||
872 | * By default, an endpoint should always transmit to the | ||
873 | * primary path, unless the SCTP user explicitly specifies the | ||
874 | * destination transport address (and possibly source | ||
875 | * transport address) to use. | ||
876 | * | ||
877 | * [If the primary is active but not most recent, bump the most | ||
878 | * recently used transport.] | ||
879 | */ | ||
880 | if (((asoc->peer.primary_path->state == SCTP_ACTIVE) || | ||
881 | (asoc->peer.primary_path->state == SCTP_UNKNOWN)) && | ||
882 | first != asoc->peer.primary_path) { | ||
883 | second = first; | ||
884 | first = asoc->peer.primary_path; | ||
885 | } | ||
886 | |||
887 | if (!second) | ||
888 | second = first; | ||
889 | /* If we failed to find a usable transport, just camp on the | ||
890 | * primary, even if it is inactive. | ||
891 | */ | ||
892 | if (!first) { | ||
893 | first = asoc->peer.primary_path; | ||
894 | second = asoc->peer.primary_path; | ||
895 | } | ||
896 | |||
897 | /* Set the active and retran transports. */ | ||
898 | asoc->peer.active_path = first; | ||
899 | asoc->peer.retran_path = second; | ||
900 | } | 846 | } |
901 | 847 | ||
902 | /* Hold a reference to an association. */ | 848 | /* Hold a reference to an association. */ |
@@ -1325,6 +1271,62 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) | |||
1325 | __func__, asoc, &asoc->peer.retran_path->ipaddr.sa); | 1271 | __func__, asoc, &asoc->peer.retran_path->ipaddr.sa); |
1326 | } | 1272 | } |
1327 | 1273 | ||
1274 | static void sctp_select_active_and_retran_path(struct sctp_association *asoc) | ||
1275 | { | ||
1276 | struct sctp_transport *trans, *trans_pri = NULL, *trans_sec = NULL; | ||
1277 | |||
1278 | /* Look for the two most recently used active transports. */ | ||
1279 | list_for_each_entry(trans, &asoc->peer.transport_addr_list, | ||
1280 | transports) { | ||
1281 | if (trans->state == SCTP_INACTIVE || | ||
1282 | trans->state == SCTP_UNCONFIRMED || | ||
1283 | trans->state == SCTP_PF) | ||
1284 | continue; | ||
1285 | if (trans_pri == NULL || | ||
1286 | trans->last_time_heard > trans_pri->last_time_heard) { | ||
1287 | trans_sec = trans_pri; | ||
1288 | trans_pri = trans; | ||
1289 | } else if (trans_sec == NULL || | ||
1290 | trans->last_time_heard > trans_sec->last_time_heard) { | ||
1291 | trans_sec = trans; | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | /* RFC 2960 6.4 Multi-Homed SCTP Endpoints | ||
1296 | * | ||
1297 | * By default, an endpoint should always transmit to the primary | ||
1298 | * path, unless the SCTP user explicitly specifies the | ||
1299 | * destination transport address (and possibly source transport | ||
1300 | * address) to use. [If the primary is active but not most recent, | ||
1301 | * bump the most recently used transport.] | ||
1302 | */ | ||
1303 | if ((asoc->peer.primary_path->state == SCTP_ACTIVE || | ||
1304 | asoc->peer.primary_path->state == SCTP_UNKNOWN) && | ||
1305 | asoc->peer.primary_path != trans_pri) { | ||
1306 | trans_sec = trans_pri; | ||
1307 | trans_pri = asoc->peer.primary_path; | ||
1308 | } | ||
1309 | |||
1310 | /* We did not find anything useful for a possible retransmission | ||
1311 | * path; either primary path that we found is the the same as | ||
1312 | * the current one, or we didn't generally find an active one. | ||
1313 | */ | ||
1314 | if (trans_sec == NULL) | ||
1315 | trans_sec = trans_pri; | ||
1316 | |||
1317 | /* If we failed to find a usable transport, just camp on the | ||
1318 | * primary, even if they are inactive. | ||
1319 | */ | ||
1320 | if (trans_pri == NULL) { | ||
1321 | trans_pri = asoc->peer.primary_path; | ||
1322 | trans_sec = asoc->peer.primary_path; | ||
1323 | } | ||
1324 | |||
1325 | /* Set the active and retran transports. */ | ||
1326 | asoc->peer.active_path = trans_pri; | ||
1327 | asoc->peer.retran_path = trans_sec; | ||
1328 | } | ||
1329 | |||
1328 | struct sctp_transport * | 1330 | struct sctp_transport * |
1329 | sctp_assoc_choose_alter_transport(struct sctp_association *asoc, | 1331 | sctp_assoc_choose_alter_transport(struct sctp_association *asoc, |
1330 | struct sctp_transport *last_sent_to) | 1332 | struct sctp_transport *last_sent_to) |