* Try to Implement load balancer for transmit & retransmit
@ 2013-12-12 20:42 Chang Xiangzhong
2013-12-12 21:05 ` Vlad Yasevich
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Chang Xiangzhong @ 2013-12-12 20:42 UTC (permalink / raw)
To: linux-sctp
The current implementation uses only one path as the "active path" and one
path as a "retran path". This patch tries to use all of the pathes for
transmission. But I'm afraid there must be something missing, such things like
state update and etcs.
The current implementation is very simple - just distribute the load on all of
the pathes - just check if it satisifes cwnd>flight_size.
And comments would be appreciated!
---
include/net/sctp/cmt.h | 5 +++-
net/sctp/Makefile | 4 +--
net/sctp/associola.c | 33 +++++++++++++++++++--
net/sctp/cmt_debug.c | 2 +-
net/sctp/outqueue.c | 73 +++++++++++++++++++++++++++++++++++-----------
net/sctp/protocol.c | 1 +
net/sctp/sm_sideeffect.c | 2 +-
7 files changed, 95 insertions(+), 25 deletions(-)
diff --git a/include/net/sctp/cmt.h b/include/net/sctp/cmt.h
index edbbfc2..858def8 100644
--- a/include/net/sctp/cmt.h
+++ b/include/net/sctp/cmt.h
@@ -47,8 +47,11 @@
extern char* cmt_print_assoc(struct sctp_association *asoc);
extern char* cmt_print_sackhdr(struct sctp_sackhdr *sack);
extern char* cmt_print_queued_tsn(struct list_head *queue,
- struct sctp_transport *transport);
+ struct sctp_transport *t);
extern char* cmt_print_cwnd(struct list_head *transport_list);
+
+ extern struct sctp_transport* sctp_assoc_most_vacant_path(
+ struct sctp_association *asoc);
#endif
/* SACK Chunk Specific Flags*/
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 626bdca..28f1f60 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1295,6 +1295,33 @@ void sctp_assoc_update(struct sctp_association *asoc,
sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
}
+struct sctp_transport*
+sctp_assoc_most_vacant_path(struct sctp_association *asoc, int threshold)
+{
+ struct sctp_transport *t, *ret = NULL;
+ int vacancy, best=-1;
+ if (threshold < 0)
+ threshold = 0;
+ list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
+ vacancy = t->cwnd - t->flight_size;
+ if (t->state != SCTP_ACTIVE || vacancy <= threshold /*t->pathmtu/4*/)
+ continue;
+ // This is in slow-start state
+ if (t->ssthresh > t->cwnd) {
+ ret = t;
+ break;
+ }
+ if (vacancy > best) {
+ best = vacancy;
+ ret = t;
+ }
+
+
+ }
+ cmt_debug("==>Find a most vacant path: %p\n", ret);
+ return ret;
+}
+
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index d20816d..9010080 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -57,13 +57,13 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
-#include <net/sctp/cmt_debug.h>
+#include <net/sctp/cmt.h>
/* Declare internal functions here. */
@@ -920,14 +920,32 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
* current cwnd).
*/
if (!list_empty(&q->retransmit)) {
- if (asoc->peer.retran_path->state = SCTP_UNCONFIRMED)
- goto sctp_flush_out;
- if (transport = asoc->peer.retran_path)
- goto retran;
- /* Switch transports & prepare the packet. */
-
- transport = asoc->peer.retran_path;
+if (q->fast_rtx && !rtx_timeout)
+{
+ struct sctp_chunk *chunk, *chunk1;
+ int chunk_size = 0; // not count the header!
+ list_for_each_entry_safe(
+ chunk, chunk1, &q->retransmit, transmitted_list) {
+ // not the one to fast_rtx
+ if (sctp_chunk_abandoned(chunk)
+ || chunk->tsn_gap_acked
+ || !chunk->fast_retransmit) {
+ continue;
+ }
+ // found the chunk to fast_rtx
+ chunk_size = ntohs(chunk->chunk_hdr->length);
+ break;
+ }
+ transport = sctp_assoc_most_vacant_path(asoc, chunk_size);
+ cmt_debug("%s: fast_rtx most vacant=%p, chunk_size=%d", __func__, transport, chunk_size);
+} else {
+ transport = sctp_assoc_most_vacant_path(asoc, -1);
+}
+ if (!transport) {
+ cmt_debug("could not find a vacant path!\n");
+ goto sctp_flush_out;
+ }
if (list_empty(&transport->send_ready)) {
list_add_tail(&transport->send_ready,
@@ -989,12 +1007,22 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
/* If there is a specified transport, use it.
* Otherwise, we want to use the active path.
*/
- new_transport = chunk->transport;
+ bool path_specified;
+retry: new_transport = chunk->transport;
if (!new_transport ||
((new_transport->state = SCTP_INACTIVE) ||
(new_transport->state = SCTP_UNCONFIRMED) ||
- (new_transport->state = SCTP_PF)))
- new_transport = asoc->peer.active_path;
+ (new_transport->state = SCTP_PF))) {
+ path_specified = false;
+ // new_transport = asoc->peer.active_path;
+ new_transport = sctp_assoc_most_vacant_path(
+ asoc, -1);
+ if (!new_transport) {// no available path
+ sctp_outq_head_data(q, chunk);
+ goto sctp_flush_out;
+ }
+ } else
+ path_specified = true;
if (new_transport->state = SCTP_UNCONFIRMED)
continue;
@@ -1032,7 +1060,18 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
switch (status) {
case SCTP_XMIT_CWND_FULL:// 3
- case SCTP_XMIT_PMTU_FULL://1
+ cmt_debug("==>CWND full\n");
+ // The App didn't specify a path, so the path
+ // was chosen by us. Then we could retry with
+ // another path
+ if (!path_specified) {
+ cmt_debug("==>retry!\n");
+ goto retry;
+ }
+ // PMTU_FULL not likely. As sctp_packet_transmit_chunk
+ // would flush the transport and transmit the next
+ // chunk in the queue if PMTU_FULL happens.
+ case SCTP_XMIT_PMTU_FULL://1
case SCTP_XMIT_RWND_FULL://2
case SCTP_XMIT_NAGLE_DELAY://4
/* We could not append this chunk, so put
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: Try to Implement load balancer for transmit & retransmit
2013-12-12 20:42 Try to Implement load balancer for transmit & retransmit Chang Xiangzhong
@ 2013-12-12 21:05 ` Vlad Yasevich
2013-12-12 21:39 ` Neil Horman
2013-12-12 21:48 ` Chang
2 siblings, 0 replies; 4+ messages in thread
From: Vlad Yasevich @ 2013-12-12 21:05 UTC (permalink / raw)
To: linux-sctp
On 12/12/2013 03:42 PM, Chang Xiangzhong wrote:
> The current implementation uses only one path as the "active path" and one
> path as a "retran path". This patch tries to use all of the pathes for
> transmission. But I'm afraid there must be something missing, such things like
> state update and etcs.
>
> The current implementation is very simple - just distribute the load on all of
> the pathes - just check if it satisifes cwnd>flight_size.
>
If you are interested in pursuing this work I recommend you look at
https://tools.ietf.org/id/draft-tuexen-tsvwg-sctp-multipath-06.txt
-vlad
> And comments would be appreciated!
> ---
> include/net/sctp/cmt.h | 5 +++-
> net/sctp/Makefile | 4 +--
> net/sctp/associola.c | 33 +++++++++++++++++++--
> net/sctp/cmt_debug.c | 2 +-
> net/sctp/outqueue.c | 73 +++++++++++++++++++++++++++++++++++-----------
> net/sctp/protocol.c | 1 +
> net/sctp/sm_sideeffect.c | 2 +-
> 7 files changed, 95 insertions(+), 25 deletions(-)
>
> diff --git a/include/net/sctp/cmt.h b/include/net/sctp/cmt.h
> index edbbfc2..858def8 100644
> --- a/include/net/sctp/cmt.h
> +++ b/include/net/sctp/cmt.h
> @@ -47,8 +47,11 @@
> extern char* cmt_print_assoc(struct sctp_association *asoc);
> extern char* cmt_print_sackhdr(struct sctp_sackhdr *sack);
> extern char* cmt_print_queued_tsn(struct list_head *queue,
> - struct sctp_transport *transport);
> + struct sctp_transport *t);
> extern char* cmt_print_cwnd(struct list_head *transport_list);
> +
> + extern struct sctp_transport* sctp_assoc_most_vacant_path(
> + struct sctp_association *asoc);
> #endif
>
> /* SACK Chunk Specific Flags*/
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 626bdca..28f1f60 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -1295,6 +1295,33 @@ void sctp_assoc_update(struct sctp_association *asoc,
> sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
> }
>
> +struct sctp_transport*
> +sctp_assoc_most_vacant_path(struct sctp_association *asoc, int threshold)
> +{
> + struct sctp_transport *t, *ret = NULL;
> + int vacancy, best=-1;
> + if (threshold < 0)
> + threshold = 0;
> + list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
> + vacancy = t->cwnd - t->flight_size;
> + if (t->state != SCTP_ACTIVE || vacancy <= threshold /*t->pathmtu/4*/)
> + continue;
> + // This is in slow-start state
> + if (t->ssthresh > t->cwnd) {
> + ret = t;
> + break;
> + }
> + if (vacancy > best) {
> + best = vacancy;
> + ret = t;
> + }
> +
> +
> + }
> + cmt_debug("==>Find a most vacant path: %p\n", ret);
> + return ret;
> +}
> +
>
> diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
> index d20816d..9010080 100644
> --- a/net/sctp/outqueue.c
> +++ b/net/sctp/outqueue.c
> @@ -57,13 +57,13 @@
>
> #include <net/sctp/sctp.h>
> #include <net/sctp/sm.h>
> -#include <net/sctp/cmt_debug.h>
> +#include <net/sctp/cmt.h>
>
>
> /* Declare internal functions here. */
> @@ -920,14 +920,32 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
> * current cwnd).
> */
> if (!list_empty(&q->retransmit)) {
> - if (asoc->peer.retran_path->state = SCTP_UNCONFIRMED)
> - goto sctp_flush_out;
> - if (transport = asoc->peer.retran_path)
> - goto retran;
>
> - /* Switch transports & prepare the packet. */
> -
> - transport = asoc->peer.retran_path;
> +if (q->fast_rtx && !rtx_timeout)
> +{
> + struct sctp_chunk *chunk, *chunk1;
> + int chunk_size = 0; // not count the header!
> + list_for_each_entry_safe(
> + chunk, chunk1, &q->retransmit, transmitted_list) {
> + // not the one to fast_rtx
> + if (sctp_chunk_abandoned(chunk)
> + || chunk->tsn_gap_acked
> + || !chunk->fast_retransmit) {
> + continue;
> + }
> + // found the chunk to fast_rtx
> + chunk_size = ntohs(chunk->chunk_hdr->length);
> + break;
> + }
> + transport = sctp_assoc_most_vacant_path(asoc, chunk_size);
> + cmt_debug("%s: fast_rtx most vacant=%p, chunk_size=%d", __func__, transport, chunk_size);
> +} else {
> + transport = sctp_assoc_most_vacant_path(asoc, -1);
> +}
> + if (!transport) {
> + cmt_debug("could not find a vacant path!\n");
> + goto sctp_flush_out;
> + }
>
> if (list_empty(&transport->send_ready)) {
> list_add_tail(&transport->send_ready,
> @@ -989,12 +1007,22 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
> /* If there is a specified transport, use it.
> * Otherwise, we want to use the active path.
> */
> - new_transport = chunk->transport;
> + bool path_specified;
> +retry: new_transport = chunk->transport;
> if (!new_transport ||
> ((new_transport->state = SCTP_INACTIVE) ||
> (new_transport->state = SCTP_UNCONFIRMED) ||
> - (new_transport->state = SCTP_PF)))
> - new_transport = asoc->peer.active_path;
> + (new_transport->state = SCTP_PF))) {
> + path_specified = false;
> + // new_transport = asoc->peer.active_path;
> + new_transport = sctp_assoc_most_vacant_path(
> + asoc, -1);
> + if (!new_transport) {// no available path
> + sctp_outq_head_data(q, chunk);
> + goto sctp_flush_out;
> + }
> + } else
> + path_specified = true;
> if (new_transport->state = SCTP_UNCONFIRMED)
> continue;
>
> @@ -1032,7 +1060,18 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
>
> switch (status) {
> case SCTP_XMIT_CWND_FULL:// 3
> - case SCTP_XMIT_PMTU_FULL://1
> + cmt_debug("==>CWND full\n");
> + // The App didn't specify a path, so the path
> + // was chosen by us. Then we could retry with
> + // another path
> + if (!path_specified) {
> + cmt_debug("==>retry!\n");
> + goto retry;
> + }
> + // PMTU_FULL not likely. As sctp_packet_transmit_chunk
> + // would flush the transport and transmit the next
> + // chunk in the queue if PMTU_FULL happens.
> + case SCTP_XMIT_PMTU_FULL://1
> case SCTP_XMIT_RWND_FULL://2
> case SCTP_XMIT_NAGLE_DELAY://4
> /* We could not append this chunk, so put
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Try to Implement load balancer for transmit & retransmit
2013-12-12 20:42 Try to Implement load balancer for transmit & retransmit Chang Xiangzhong
2013-12-12 21:05 ` Vlad Yasevich
@ 2013-12-12 21:39 ` Neil Horman
2013-12-12 21:48 ` Chang
2 siblings, 0 replies; 4+ messages in thread
From: Neil Horman @ 2013-12-12 21:39 UTC (permalink / raw)
To: linux-sctp
On Thu, Dec 12, 2013 at 09:42:32PM +0100, Chang Xiangzhong wrote:
> The current implementation uses only one path as the "active path" and one
> path as a "retran path". This patch tries to use all of the pathes for
> transmission. But I'm afraid there must be something missing, such things like
> state update and etcs.
>
> The current implementation is very simple - just distribute the load on all of
> the pathes - just check if it satisifes cwnd>flight_size.
>
> And comments would be appreciated!
> ---
> include/net/sctp/cmt.h | 5 +++-
> net/sctp/Makefile | 4 +--
> net/sctp/associola.c | 33 +++++++++++++++++++--
> net/sctp/cmt_debug.c | 2 +-
> net/sctp/outqueue.c | 73 +++++++++++++++++++++++++++++++++++-----------
> net/sctp/protocol.c | 1 +
> net/sctp/sm_sideeffect.c | 2 +-
> 7 files changed, 95 insertions(+), 25 deletions(-)
>
> diff --git a/include/net/sctp/cmt.h b/include/net/sctp/cmt.h
> index edbbfc2..858def8 100644
> --- a/include/net/sctp/cmt.h
> +++ b/include/net/sctp/cmt.h
> @@ -47,8 +47,11 @@
> extern char* cmt_print_assoc(struct sctp_association *asoc);
> extern char* cmt_print_sackhdr(struct sctp_sackhdr *sack);
> extern char* cmt_print_queued_tsn(struct list_head *queue,
> - struct sctp_transport *transport);
> + struct sctp_transport *t);
> extern char* cmt_print_cwnd(struct list_head *transport_list);
> +
> + extern struct sctp_transport* sctp_assoc_most_vacant_path(
> + struct sctp_association *asoc);
> #endif
>
> /* SACK Chunk Specific Flags*/
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 626bdca..28f1f60 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -1295,6 +1295,33 @@ void sctp_assoc_update(struct sctp_association *asoc,
> sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
> }
>
> +struct sctp_transport*
> +sctp_assoc_most_vacant_path(struct sctp_association *asoc, int threshold)
> +{
> + struct sctp_transport *t, *ret = NULL;
> + int vacancy, best=-1;
> + if (threshold < 0)
> + threshold = 0;
> + list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
> + vacancy = t->cwnd - t->flight_size;
> + if (t->state != SCTP_ACTIVE || vacancy <= threshold /*t->pathmtu/4*/)
> + continue;
> + // This is in slow-start state
> + if (t->ssthresh > t->cwnd) {
> + ret = t;
> + break;
> + }
> + if (vacancy > best) {
> + best = vacancy;
> + ret = t;
> + }
> +
> +
> + }
> + cmt_debug("==>Find a most vacant path: %p\n", ret);
> + return ret;
> +}
> +
>
> diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
> index d20816d..9010080 100644
> --- a/net/sctp/outqueue.c
> +++ b/net/sctp/outqueue.c
> @@ -57,13 +57,13 @@
>
> #include <net/sctp/sctp.h>
> #include <net/sctp/sm.h>
> -#include <net/sctp/cmt_debug.h>
> +#include <net/sctp/cmt.h>
>
>
> /* Declare internal functions here. */
> @@ -920,14 +920,32 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
> * current cwnd).
> */
> if (!list_empty(&q->retransmit)) {
> - if (asoc->peer.retran_path->state = SCTP_UNCONFIRMED)
> - goto sctp_flush_out;
> - if (transport = asoc->peer.retran_path)
> - goto retran;
>
> - /* Switch transports & prepare the packet. */
> -
> - transport = asoc->peer.retran_path;
> +if (q->fast_rtx && !rtx_timeout)
> +{
> + struct sctp_chunk *chunk, *chunk1;
> + int chunk_size = 0; // not count the header!
> + list_for_each_entry_safe(
> + chunk, chunk1, &q->retransmit, transmitted_list) {
> + // not the one to fast_rtx
> + if (sctp_chunk_abandoned(chunk)
> + || chunk->tsn_gap_acked
> + || !chunk->fast_retransmit) {
> + continue;
> + }
> + // found the chunk to fast_rtx
> + chunk_size = ntohs(chunk->chunk_hdr->length);
> + break;
> + }
> + transport = sctp_assoc_most_vacant_path(asoc, chunk_size);
> + cmt_debug("%s: fast_rtx most vacant=%p, chunk_size=%d", __func__, transport, chunk_size);
> +} else {
> + transport = sctp_assoc_most_vacant_path(asoc, -1);
> +}
> + if (!transport) {
> + cmt_debug("could not find a vacant path!\n");
> + goto sctp_flush_out;
> + }
>
> if (list_empty(&transport->send_ready)) {
> list_add_tail(&transport->send_ready,
> @@ -989,12 +1007,22 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
> /* If there is a specified transport, use it.
> * Otherwise, we want to use the active path.
> */
> - new_transport = chunk->transport;
> + bool path_specified;
> +retry: new_transport = chunk->transport;
> if (!new_transport ||
> ((new_transport->state = SCTP_INACTIVE) ||
> (new_transport->state = SCTP_UNCONFIRMED) ||
> - (new_transport->state = SCTP_PF)))
> - new_transport = asoc->peer.active_path;
> + (new_transport->state = SCTP_PF))) {
> + path_specified = false;
> + // new_transport = asoc->peer.active_path;
> + new_transport = sctp_assoc_most_vacant_path(
> + asoc, -1);
> + if (!new_transport) {// no available path
> + sctp_outq_head_data(q, chunk);
> + goto sctp_flush_out;
> + }
> + } else
> + path_specified = true;
> if (new_transport->state = SCTP_UNCONFIRMED)
> continue;
>
> @@ -1032,7 +1060,18 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
>
> switch (status) {
> case SCTP_XMIT_CWND_FULL:// 3
> - case SCTP_XMIT_PMTU_FULL://1
> + cmt_debug("==>CWND full\n");
> + // The App didn't specify a path, so the path
> + // was chosen by us. Then we could retry with
> + // another path
> + if (!path_specified) {
> + cmt_debug("==>retry!\n");
> + goto retry;
> + }
> + // PMTU_FULL not likely. As sctp_packet_transmit_chunk
> + // would flush the transport and transmit the next
> + // chunk in the queue if PMTU_FULL happens.
> + case SCTP_XMIT_PMTU_FULL://1
> case SCTP_XMIT_RWND_FULL://2
> case SCTP_XMIT_NAGLE_DELAY://4
> /* We could not append this chunk, so put
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Agree with vlad. This patch just doles out new aasociations accross less loaded
transports (using a very transient metric). What you want to do is
multipathing.
Neil
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Try to Implement load balancer for transmit & retransmit
2013-12-12 20:42 Try to Implement load balancer for transmit & retransmit Chang Xiangzhong
2013-12-12 21:05 ` Vlad Yasevich
2013-12-12 21:39 ` Neil Horman
@ 2013-12-12 21:48 ` Chang
2 siblings, 0 replies; 4+ messages in thread
From: Chang @ 2013-12-12 21:48 UTC (permalink / raw)
To: linux-sctp
Yeah,
In my essay, I would implement SFR and CUC algorithms to manage the cwnd
increment/decrement, but in current implementation, the load is not
balanced to all of the pathes. So my 1st step is to evenly distribute
the load
Cheers
On 12/12/2013 10:39 PM, Neil Horman wrote:
> On Thu, Dec 12, 2013 at 09:42:32PM +0100, Chang Xiangzhong wrote:
>> The current implementation uses only one path as the "active path" and one
>> path as a "retran path". This patch tries to use all of the pathes for
>> transmission. But I'm afraid there must be something missing, such things like
>> state update and etcs.
>>
>> The current implementation is very simple - just distribute the load on all of
>> the pathes - just check if it satisifes cwnd>flight_size.
>>
>> And comments would be appreciated!
>> ---
>> include/net/sctp/cmt.h | 5 +++-
>> net/sctp/Makefile | 4 +--
>> net/sctp/associola.c | 33 +++++++++++++++++++--
>> net/sctp/cmt_debug.c | 2 +-
>> net/sctp/outqueue.c | 73 +++++++++++++++++++++++++++++++++++-----------
>> net/sctp/protocol.c | 1 +
>> net/sctp/sm_sideeffect.c | 2 +-
>> 7 files changed, 95 insertions(+), 25 deletions(-)
>>
>> diff --git a/include/net/sctp/cmt.h b/include/net/sctp/cmt.h
>> index edbbfc2..858def8 100644
>> --- a/include/net/sctp/cmt.h
>> +++ b/include/net/sctp/cmt.h
>> @@ -47,8 +47,11 @@
>> extern char* cmt_print_assoc(struct sctp_association *asoc);
>> extern char* cmt_print_sackhdr(struct sctp_sackhdr *sack);
>> extern char* cmt_print_queued_tsn(struct list_head *queue,
>> - struct sctp_transport *transport);
>> + struct sctp_transport *t);
>> extern char* cmt_print_cwnd(struct list_head *transport_list);
>> +
>> + extern struct sctp_transport* sctp_assoc_most_vacant_path(
>> + struct sctp_association *asoc);
>> #endif
>>
>> /* SACK Chunk Specific Flags*/
>> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
>> index 626bdca..28f1f60 100644
>> --- a/net/sctp/associola.c
>> +++ b/net/sctp/associola.c
>> @@ -1295,6 +1295,33 @@ void sctp_assoc_update(struct sctp_association *asoc,
>> sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
>> }
>>
>> +struct sctp_transport*
>> +sctp_assoc_most_vacant_path(struct sctp_association *asoc, int threshold)
>> +{
>> + struct sctp_transport *t, *ret = NULL;
>> + int vacancy, best=-1;
>> + if (threshold < 0)
>> + threshold = 0;
>> + list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
>> + vacancy = t->cwnd - t->flight_size;
>> + if (t->state != SCTP_ACTIVE || vacancy <= threshold /*t->pathmtu/4*/)
>> + continue;
>> + // This is in slow-start state
>> + if (t->ssthresh > t->cwnd) {
>> + ret = t;
>> + break;
>> + }
>> + if (vacancy > best) {
>> + best = vacancy;
>> + ret = t;
>> + }
>> +
>> +
>> + }
>> + cmt_debug("==>Find a most vacant path: %p\n", ret);
>> + return ret;
>> +}
>> +
>>
>> diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
>> index d20816d..9010080 100644
>> --- a/net/sctp/outqueue.c
>> +++ b/net/sctp/outqueue.c
>> @@ -57,13 +57,13 @@
>>
>> #include <net/sctp/sctp.h>
>> #include <net/sctp/sm.h>
>> -#include <net/sctp/cmt_debug.h>
>> +#include <net/sctp/cmt.h>
>>
>>
>> /* Declare internal functions here. */
>> @@ -920,14 +920,32 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
>> * current cwnd).
>> */
>> if (!list_empty(&q->retransmit)) {
>> - if (asoc->peer.retran_path->state = SCTP_UNCONFIRMED)
>> - goto sctp_flush_out;
>> - if (transport = asoc->peer.retran_path)
>> - goto retran;
>>
>> - /* Switch transports & prepare the packet. */
>> -
>> - transport = asoc->peer.retran_path;
>> +if (q->fast_rtx && !rtx_timeout)
>> +{
>> + struct sctp_chunk *chunk, *chunk1;
>> + int chunk_size = 0; // not count the header!
>> + list_for_each_entry_safe(
>> + chunk, chunk1, &q->retransmit, transmitted_list) {
>> + // not the one to fast_rtx
>> + if (sctp_chunk_abandoned(chunk)
>> + || chunk->tsn_gap_acked
>> + || !chunk->fast_retransmit) {
>> + continue;
>> + }
>> + // found the chunk to fast_rtx
>> + chunk_size = ntohs(chunk->chunk_hdr->length);
>> + break;
>> + }
>> + transport = sctp_assoc_most_vacant_path(asoc, chunk_size);
>> + cmt_debug("%s: fast_rtx most vacant=%p, chunk_size=%d", __func__, transport, chunk_size);
>> +} else {
>> + transport = sctp_assoc_most_vacant_path(asoc, -1);
>> +}
>> + if (!transport) {
>> + cmt_debug("could not find a vacant path!\n");
>> + goto sctp_flush_out;
>> + }
>>
>> if (list_empty(&transport->send_ready)) {
>> list_add_tail(&transport->send_ready,
>> @@ -989,12 +1007,22 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
>> /* If there is a specified transport, use it.
>> * Otherwise, we want to use the active path.
>> */
>> - new_transport = chunk->transport;
>> + bool path_specified;
>> +retry: new_transport = chunk->transport;
>> if (!new_transport ||
>> ((new_transport->state = SCTP_INACTIVE) ||
>> (new_transport->state = SCTP_UNCONFIRMED) ||
>> - (new_transport->state = SCTP_PF)))
>> - new_transport = asoc->peer.active_path;
>> + (new_transport->state = SCTP_PF))) {
>> + path_specified = false;
>> + // new_transport = asoc->peer.active_path;
>> + new_transport = sctp_assoc_most_vacant_path(
>> + asoc, -1);
>> + if (!new_transport) {// no available path
>> + sctp_outq_head_data(q, chunk);
>> + goto sctp_flush_out;
>> + }
>> + } else
>> + path_specified = true;
>> if (new_transport->state = SCTP_UNCONFIRMED)
>> continue;
>>
>> @@ -1032,7 +1060,18 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
>>
>> switch (status) {
>> case SCTP_XMIT_CWND_FULL:// 3
>> - case SCTP_XMIT_PMTU_FULL://1
>> + cmt_debug("==>CWND full\n");
>> + // The App didn't specify a path, so the path
>> + // was chosen by us. Then we could retry with
>> + // another path
>> + if (!path_specified) {
>> + cmt_debug("==>retry!\n");
>> + goto retry;
>> + }
>> + // PMTU_FULL not likely. As sctp_packet_transmit_chunk
>> + // would flush the transport and transmit the next
>> + // chunk in the queue if PMTU_FULL happens.
>> + case SCTP_XMIT_PMTU_FULL://1
>> case SCTP_XMIT_RWND_FULL://2
>> case SCTP_XMIT_NAGLE_DELAY://4
>> /* We could not append this chunk, so put
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
> Agree with vlad. This patch just doles out new aasociations accross less loaded
> transports (using a very transient metric). What you want to do is
> multipathing.
>
> Neil
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-12-12 21:48 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-12 20:42 Try to Implement load balancer for transmit & retransmit Chang Xiangzhong
2013-12-12 21:05 ` Vlad Yasevich
2013-12-12 21:39 ` Neil Horman
2013-12-12 21:48 ` Chang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.