Skip to content

Commit

Permalink
net: sctp: refactor active path selection
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Daniel Borkmann authored and davem330 committed Jun 11, 2014
1 parent 67cb936 commit b82e8f3
Showing 1 changed file with 61 additions and 59 deletions.
120 changes: 61 additions & 59 deletions net/sctp/associola.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include <net/sctp/sm.h>

/* 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_free_asconf_acks(struct sctp_association *asoc);
static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
Expand Down Expand Up @@ -774,9 +775,6 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
sctp_transport_cmd_t command,
sctp_sn_error_t error)
{
struct sctp_transport *t = NULL;
struct sctp_transport *first;
struct sctp_transport *second;
struct sctp_ulpevent *event;
struct sockaddr_storage addr;
int spc_state = 0;
Expand Down Expand Up @@ -829,74 +827,22 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
return;
}

/* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
* user.
/* Generate and send a SCTP_PEER_ADDR_CHANGE notification
* to the user.
*/
if (ulp_notify) {
memset(&addr, 0, sizeof(struct sockaddr_storage));
memcpy(&addr, &transport->ipaddr,
transport->af_specific->sockaddr_len);

event = sctp_ulpevent_make_peer_addr_change(asoc, &addr,
0, spc_state, error, GFP_ATOMIC);
if (event)
sctp_ulpq_tail_event(&asoc->ulpq, event);
}

/* Select new active and retran paths. */

/* 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;
sctp_select_active_and_retran_path(asoc);
}

/* Hold a reference to an association. */
Expand Down Expand Up @@ -1325,6 +1271,62 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
__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 *
sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
struct sctp_transport *last_sent_to)
Expand Down

0 comments on commit b82e8f3

Please sign in to comment.