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>
This commit is contained in:
parent
67cb9366ff
commit
b82e8f31ac
|
@ -55,6 +55,7 @@
|
||||||
#include <net/sctp/sm.h>
|
#include <net/sctp/sm.h>
|
||||||
|
|
||||||
/* Forward declarations for internal functions. */
|
/* Forward declarations for internal functions. */
|
||||||
|
static void sctp_select_active_and_retran_path(struct sctp_association *asoc);
|
||||||
static void sctp_assoc_bh_rcv(struct work_struct *work);
|
static void sctp_assoc_bh_rcv(struct work_struct *work);
|
||||||
static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
|
static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
|
||||||
static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
|
static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
|
||||||
|
@ -774,9 +775,6 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
|
||||||
sctp_transport_cmd_t command,
|
sctp_transport_cmd_t command,
|
||||||
sctp_sn_error_t error)
|
sctp_sn_error_t error)
|
||||||
{
|
{
|
||||||
struct sctp_transport *t = NULL;
|
|
||||||
struct sctp_transport *first;
|
|
||||||
struct sctp_transport *second;
|
|
||||||
struct sctp_ulpevent *event;
|
struct sctp_ulpevent *event;
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
int spc_state = 0;
|
int spc_state = 0;
|
||||||
|
@ -829,13 +827,14 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
|
/* Generate and send a SCTP_PEER_ADDR_CHANGE notification
|
||||||
* user.
|
* to the user.
|
||||||
*/
|
*/
|
||||||
if (ulp_notify) {
|
if (ulp_notify) {
|
||||||
memset(&addr, 0, sizeof(struct sockaddr_storage));
|
memset(&addr, 0, sizeof(struct sockaddr_storage));
|
||||||
memcpy(&addr, &transport->ipaddr,
|
memcpy(&addr, &transport->ipaddr,
|
||||||
transport->af_specific->sockaddr_len);
|
transport->af_specific->sockaddr_len);
|
||||||
|
|
||||||
event = sctp_ulpevent_make_peer_addr_change(asoc, &addr,
|
event = sctp_ulpevent_make_peer_addr_change(asoc, &addr,
|
||||||
0, spc_state, error, GFP_ATOMIC);
|
0, spc_state, error, GFP_ATOMIC);
|
||||||
if (event)
|
if (event)
|
||||||
|
@ -843,60 +842,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select new active and retran paths. */
|
/* Select new active and retran paths. */
|
||||||
|
sctp_select_active_and_retran_path(asoc);
|
||||||
/* Look for the two most recently used active transports.
|
|
||||||
*
|
|
||||||
* This code produces the wrong ordering whenever jiffies
|
|
||||||
* rolls over, but we still get usable transports, so we don't
|
|
||||||
* worry about it.
|
|
||||||
*/
|
|
||||||
first = NULL; second = NULL;
|
|
||||||
|
|
||||||
list_for_each_entry(t, &asoc->peer.transport_addr_list,
|
|
||||||
transports) {
|
|
||||||
|
|
||||||
if ((t->state == SCTP_INACTIVE) ||
|
|
||||||
(t->state == SCTP_UNCONFIRMED) ||
|
|
||||||
(t->state == SCTP_PF))
|
|
||||||
continue;
|
|
||||||
if (!first || t->last_time_heard > first->last_time_heard) {
|
|
||||||
second = first;
|
|
||||||
first = t;
|
|
||||||
} else if (!second ||
|
|
||||||
t->last_time_heard > second->last_time_heard)
|
|
||||||
second = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RFC 2960 6.4 Multi-Homed SCTP Endpoints
|
|
||||||
*
|
|
||||||
* By default, an endpoint should always transmit to the
|
|
||||||
* primary path, unless the SCTP user explicitly specifies the
|
|
||||||
* destination transport address (and possibly source
|
|
||||||
* transport address) to use.
|
|
||||||
*
|
|
||||||
* [If the primary is active but not most recent, bump the most
|
|
||||||
* recently used transport.]
|
|
||||||
*/
|
|
||||||
if (((asoc->peer.primary_path->state == SCTP_ACTIVE) ||
|
|
||||||
(asoc->peer.primary_path->state == SCTP_UNKNOWN)) &&
|
|
||||||
first != asoc->peer.primary_path) {
|
|
||||||
second = first;
|
|
||||||
first = asoc->peer.primary_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!second)
|
|
||||||
second = first;
|
|
||||||
/* If we failed to find a usable transport, just camp on the
|
|
||||||
* primary, even if it is inactive.
|
|
||||||
*/
|
|
||||||
if (!first) {
|
|
||||||
first = asoc->peer.primary_path;
|
|
||||||
second = asoc->peer.primary_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the active and retran transports. */
|
|
||||||
asoc->peer.active_path = first;
|
|
||||||
asoc->peer.retran_path = second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hold a reference to an association. */
|
/* Hold a reference to an association. */
|
||||||
|
@ -1325,6 +1271,62 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
|
||||||
__func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
|
__func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sctp_select_active_and_retran_path(struct sctp_association *asoc)
|
||||||
|
{
|
||||||
|
struct sctp_transport *trans, *trans_pri = NULL, *trans_sec = NULL;
|
||||||
|
|
||||||
|
/* Look for the two most recently used active transports. */
|
||||||
|
list_for_each_entry(trans, &asoc->peer.transport_addr_list,
|
||||||
|
transports) {
|
||||||
|
if (trans->state == SCTP_INACTIVE ||
|
||||||
|
trans->state == SCTP_UNCONFIRMED ||
|
||||||
|
trans->state == SCTP_PF)
|
||||||
|
continue;
|
||||||
|
if (trans_pri == NULL ||
|
||||||
|
trans->last_time_heard > trans_pri->last_time_heard) {
|
||||||
|
trans_sec = trans_pri;
|
||||||
|
trans_pri = trans;
|
||||||
|
} else if (trans_sec == NULL ||
|
||||||
|
trans->last_time_heard > trans_sec->last_time_heard) {
|
||||||
|
trans_sec = trans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RFC 2960 6.4 Multi-Homed SCTP Endpoints
|
||||||
|
*
|
||||||
|
* By default, an endpoint should always transmit to the primary
|
||||||
|
* path, unless the SCTP user explicitly specifies the
|
||||||
|
* destination transport address (and possibly source transport
|
||||||
|
* address) to use. [If the primary is active but not most recent,
|
||||||
|
* bump the most recently used transport.]
|
||||||
|
*/
|
||||||
|
if ((asoc->peer.primary_path->state == SCTP_ACTIVE ||
|
||||||
|
asoc->peer.primary_path->state == SCTP_UNKNOWN) &&
|
||||||
|
asoc->peer.primary_path != trans_pri) {
|
||||||
|
trans_sec = trans_pri;
|
||||||
|
trans_pri = asoc->peer.primary_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We did not find anything useful for a possible retransmission
|
||||||
|
* path; either primary path that we found is the the same as
|
||||||
|
* the current one, or we didn't generally find an active one.
|
||||||
|
*/
|
||||||
|
if (trans_sec == NULL)
|
||||||
|
trans_sec = trans_pri;
|
||||||
|
|
||||||
|
/* If we failed to find a usable transport, just camp on the
|
||||||
|
* primary, even if they are inactive.
|
||||||
|
*/
|
||||||
|
if (trans_pri == NULL) {
|
||||||
|
trans_pri = asoc->peer.primary_path;
|
||||||
|
trans_sec = asoc->peer.primary_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the active and retran transports. */
|
||||||
|
asoc->peer.active_path = trans_pri;
|
||||||
|
asoc->peer.retran_path = trans_sec;
|
||||||
|
}
|
||||||
|
|
||||||
struct sctp_transport *
|
struct sctp_transport *
|
||||||
sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
|
sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
|
||||||
struct sctp_transport *last_sent_to)
|
struct sctp_transport *last_sent_to)
|
||||||
|
|
Loading…
Reference in New Issue