All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
@ 2012-06-26 20:31 ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-26 20:31 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>
---
 include/net/sctp/structs.h |    5 ++++-
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/output.c          |    9 +++++++--
 net/sctp/sm_make_chunk.c   |    8 ++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/tsnmap.c          |    5 ++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 8 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..712bf09 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -910,7 +910,10 @@ struct sctp_transport {
 		pmtu_pending:1,
 
 		/* Is this structure kfree()able? */
-		malloced:1;
+		malloced:1,
+
+		/* Has this transport moved the ctsn since we last sacked */
+		moved_ctsn:1;
 
 	struct flowi fl;
 
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..c9f47b6 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+		struct sctp_transport *trans;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
 			asoc->a_rwnd = asoc->rwnd;
+
+			if (chunk->transport && !chunk->transport->moved_ctsn)
+				return retval;
+
 			sack = sctp_make_sack(asoc);
 			if (sack) {
 				retval = sctp_packet_append_chunk(pkt, sack);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..bad469b 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	__u16 num_gabs, num_dup_tsns;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +806,13 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated, clear the moved_tsn information
+	 * from all the transports
+	 */
+	list_for_each_entry(trans, &asoc->peer.transport_addr_list, transports) {
+		trans->moved_ctsn = 0;
+	}
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..619c638 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,8 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->moved_ctsn = 1;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
@ 2012-06-26 20:31 ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-26 20:31 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>
---
 include/net/sctp/structs.h |    5 ++++-
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/output.c          |    9 +++++++--
 net/sctp/sm_make_chunk.c   |    8 ++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/tsnmap.c          |    5 ++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 8 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..712bf09 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -910,7 +910,10 @@ struct sctp_transport {
 		pmtu_pending:1,
 
 		/* Is this structure kfree()able? */
-		malloced:1;
+		malloced:1,
+
+		/* Has this transport moved the ctsn since we last sacked */
+		moved_ctsn:1;
 
 	struct flowi fl;
 
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..c9f47b6 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+		struct sctp_transport *trans;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
 			asoc->a_rwnd = asoc->rwnd;
+
+			if (chunk->transport && !chunk->transport->moved_ctsn)
+				return retval;
+
 			sack = sctp_make_sack(asoc);
 			if (sack) {
 				retval = sctp_packet_append_chunk(pkt, sack);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..bad469b 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	__u16 num_gabs, num_dup_tsns;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +806,13 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated, clear the moved_tsn information
+	 * from all the transports
+	 */
+	list_for_each_entry(trans, &asoc->peer.transport_addr_list, transports) {
+		trans->moved_ctsn = 0;
+	}
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..619c638 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,8 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->moved_ctsn = 1;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
  2012-06-26 20:31 ` Neil Horman
@ 2012-06-27  4:05   ` David Miller
  -1 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-06-27  4:05 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Tue, 26 Jun 2012 16:31:44 -0400

> @@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>  	 */
>  	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
>  	    !pkt->has_cookie_echo) {
> -		struct sctp_association *asoc;
>  		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +		struct sctp_transport *trans;
> +
>  		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>  
>  		/* If the SACK timer is running, we have a pending SACK */
>  		if (timer_pending(timer)) {
>  			struct sctp_chunk *sack;
>  			asoc->a_rwnd = asoc->rwnd;
> +
> +			if (chunk->transport && !chunk->transport->moved_ctsn)
> +				return retval;
> +
>  			sack = sctp_make_sack(asoc);
>  			if (sack) {
>  				retval = sctp_packet_append_chunk(pkt, sack);

The new local variable 'trans' seems to be unused.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
@ 2012-06-27  4:05   ` David Miller
  0 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-06-27  4:05 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Tue, 26 Jun 2012 16:31:44 -0400

> @@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>  	 */
>  	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
>  	    !pkt->has_cookie_echo) {
> -		struct sctp_association *asoc;
>  		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +		struct sctp_transport *trans;
> +
>  		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>  
>  		/* If the SACK timer is running, we have a pending SACK */
>  		if (timer_pending(timer)) {
>  			struct sctp_chunk *sack;
>  			asoc->a_rwnd = asoc->rwnd;
> +
> +			if (chunk->transport && !chunk->transport->moved_ctsn)
> +				return retval;
> +
>  			sack = sctp_make_sack(asoc);
>  			if (sack) {
>  				retval = sctp_packet_append_chunk(pkt, sack);

The new local variable 'trans' seems to be unused.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
  2012-06-27  4:05   ` David Miller
@ 2012-06-27 10:24     ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-27 10:24 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Tue, Jun 26, 2012 at 09:05:04PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Tue, 26 Jun 2012 16:31:44 -0400
> 
> > @@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
> >  	 */
> >  	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
> >  	    !pkt->has_cookie_echo) {
> > -		struct sctp_association *asoc;
> >  		struct timer_list *timer;
> > -		asoc = pkt->transport->asoc;
> > +		struct sctp_association *asoc = pkt->transport->asoc;
> > +		struct sctp_transport *trans;
> > +
> >  		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
> >  
> >  		/* If the SACK timer is running, we have a pending SACK */
> >  		if (timer_pending(timer)) {
> >  			struct sctp_chunk *sack;
> >  			asoc->a_rwnd = asoc->rwnd;
> > +
> > +			if (chunk->transport && !chunk->transport->moved_ctsn)
> > +				return retval;
> > +
> >  			sack = sctp_make_sack(asoc);
> >  			if (sack) {
> >  				retval = sctp_packet_append_chunk(pkt, sack);
> 
> The new local variable 'trans' seems to be unused.
> 
Crap, thank you Dave, that was a holdover from an initial pass I had made in
writing this.  I'll repost with that removed once Vald has a chance to look this
over
Neil

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
@ 2012-06-27 10:24     ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-27 10:24 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Tue, Jun 26, 2012 at 09:05:04PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Tue, 26 Jun 2012 16:31:44 -0400
> 
> > @@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
> >  	 */
> >  	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
> >  	    !pkt->has_cookie_echo) {
> > -		struct sctp_association *asoc;
> >  		struct timer_list *timer;
> > -		asoc = pkt->transport->asoc;
> > +		struct sctp_association *asoc = pkt->transport->asoc;
> > +		struct sctp_transport *trans;
> > +
> >  		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
> >  
> >  		/* If the SACK timer is running, we have a pending SACK */
> >  		if (timer_pending(timer)) {
> >  			struct sctp_chunk *sack;
> >  			asoc->a_rwnd = asoc->rwnd;
> > +
> > +			if (chunk->transport && !chunk->transport->moved_ctsn)
> > +				return retval;
> > +
> >  			sack = sctp_make_sack(asoc);
> >  			if (sack) {
> >  				retval = sctp_packet_append_chunk(pkt, sack);
> 
> The new local variable 'trans' seems to be unused.
> 
Crap, thank you Dave, that was a holdover from an initial pass I had made in
writing this.  I'll repost with that removed once Vald has a chance to look this
over
Neil


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
  2012-06-27 10:24     ` Neil Horman
@ 2012-06-27 13:20       ` Vlad Yasevich
  -1 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-27 13:20 UTC (permalink / raw)
  To: Neil Horman; +Cc: David Miller, netdev, linux-sctp

On 06/27/2012 06:24 AM, Neil Horman wrote:
> On Tue, Jun 26, 2012 at 09:05:04PM -0700, David Miller wrote:
>> From: Neil Horman<nhorman@tuxdriver.com>
>> Date: Tue, 26 Jun 2012 16:31:44 -0400
>>
>>> @@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>>>   	 */
>>>   	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
>>>   	!pkt->has_cookie_echo) {
>>> -		struct sctp_association *asoc;
>>>   		struct timer_list *timer;
>>> -		asoc = pkt->transport->asoc;
>>> +		struct sctp_association *asoc = pkt->transport->asoc;
>>> +		struct sctp_transport *trans;
>>> +
>>>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>>>
>>>   		/* If the SACK timer is running, we have a pending SACK */
>>>   		if (timer_pending(timer)) {
>>>   			struct sctp_chunk *sack;
>>>   			asoc->a_rwnd = asoc->rwnd;
>>> +
>>> +			if (chunk->transport&&  !chunk->transport->moved_ctsn)
>>> +				return retval;
>>> +
>>>   			sack = sctp_make_sack(asoc);
>>>   			if (sack) {
>>>   				retval = sctp_packet_append_chunk(pkt, sack);
>>
>> The new local variable 'trans' seems to be unused.
>>
> Crap, thank you Dave, that was a holdover from an initial pass I had made in
> writing this.  I'll repost with that removed once Vald has a chance to look this
> over
> Neil
>

Also, may want to move a_rwnd adjustment to after the new if clause.  No 
sense adjusting it if we are just going to bail.

-vlad

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
@ 2012-06-27 13:20       ` Vlad Yasevich
  0 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-27 13:20 UTC (permalink / raw)
  To: Neil Horman; +Cc: David Miller, netdev, linux-sctp

On 06/27/2012 06:24 AM, Neil Horman wrote:
> On Tue, Jun 26, 2012 at 09:05:04PM -0700, David Miller wrote:
>> From: Neil Horman<nhorman@tuxdriver.com>
>> Date: Tue, 26 Jun 2012 16:31:44 -0400
>>
>>> @@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>>>   	 */
>>>   	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
>>>   	!pkt->has_cookie_echo) {
>>> -		struct sctp_association *asoc;
>>>   		struct timer_list *timer;
>>> -		asoc = pkt->transport->asoc;
>>> +		struct sctp_association *asoc = pkt->transport->asoc;
>>> +		struct sctp_transport *trans;
>>> +
>>>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>>>
>>>   		/* If the SACK timer is running, we have a pending SACK */
>>>   		if (timer_pending(timer)) {
>>>   			struct sctp_chunk *sack;
>>>   			asoc->a_rwnd = asoc->rwnd;
>>> +
>>> +			if (chunk->transport&&  !chunk->transport->moved_ctsn)
>>> +				return retval;
>>> +
>>>   			sack = sctp_make_sack(asoc);
>>>   			if (sack) {
>>>   				retval = sctp_packet_append_chunk(pkt, sack);
>>
>> The new local variable 'trans' seems to be unused.
>>
> Crap, thank you Dave, that was a holdover from an initial pass I had made in
> writing this.  I'll repost with that removed once Vald has a chance to look this
> over
> Neil
>

Also, may want to move a_rwnd adjustment to after the new if clause.  No 
sense adjusting it if we are just going to bail.

-vlad

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
  2012-06-27 13:20       ` Vlad Yasevich
@ 2012-06-27 13:22         ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-27 13:22 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: David Miller, netdev, linux-sctp

On Wed, Jun 27, 2012 at 09:20:57AM -0400, Vlad Yasevich wrote:
> On 06/27/2012 06:24 AM, Neil Horman wrote:
> >On Tue, Jun 26, 2012 at 09:05:04PM -0700, David Miller wrote:
> >>From: Neil Horman<nhorman@tuxdriver.com>
> >>Date: Tue, 26 Jun 2012 16:31:44 -0400
> >>
> >>>@@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
> >>>  	 */
> >>>  	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
> >>>  	!pkt->has_cookie_echo) {
> >>>-		struct sctp_association *asoc;
> >>>  		struct timer_list *timer;
> >>>-		asoc = pkt->transport->asoc;
> >>>+		struct sctp_association *asoc = pkt->transport->asoc;
> >>>+		struct sctp_transport *trans;
> >>>+
> >>>  		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
> >>>
> >>>  		/* If the SACK timer is running, we have a pending SACK */
> >>>  		if (timer_pending(timer)) {
> >>>  			struct sctp_chunk *sack;
> >>>  			asoc->a_rwnd = asoc->rwnd;
> >>>+
> >>>+			if (chunk->transport&&  !chunk->transport->moved_ctsn)
> >>>+				return retval;
> >>>+
> >>>  			sack = sctp_make_sack(asoc);
> >>>  			if (sack) {
> >>>  				retval = sctp_packet_append_chunk(pkt, sack);
> >>
> >>The new local variable 'trans' seems to be unused.
> >>
> >Crap, thank you Dave, that was a holdover from an initial pass I had made in
> >writing this.  I'll repost with that removed once Vald has a chance to look this
> >over
> >Neil
> >
> 
> Also, may want to move a_rwnd adjustment to after the new if clause.
> No sense adjusting it if we are just going to bail.
> 
> -vlad
> 

copy that, I'll make both changes and repost.  Thanks!
Neil

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks
@ 2012-06-27 13:22         ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-27 13:22 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: David Miller, netdev, linux-sctp

On Wed, Jun 27, 2012 at 09:20:57AM -0400, Vlad Yasevich wrote:
> On 06/27/2012 06:24 AM, Neil Horman wrote:
> >On Tue, Jun 26, 2012 at 09:05:04PM -0700, David Miller wrote:
> >>From: Neil Horman<nhorman@tuxdriver.com>
> >>Date: Tue, 26 Jun 2012 16:31:44 -0400
> >>
> >>>@@ -240,15 +240,20 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
> >>>  	 */
> >>>  	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
> >>>  	!pkt->has_cookie_echo) {
> >>>-		struct sctp_association *asoc;
> >>>  		struct timer_list *timer;
> >>>-		asoc = pkt->transport->asoc;
> >>>+		struct sctp_association *asoc = pkt->transport->asoc;
> >>>+		struct sctp_transport *trans;
> >>>+
> >>>  		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
> >>>
> >>>  		/* If the SACK timer is running, we have a pending SACK */
> >>>  		if (timer_pending(timer)) {
> >>>  			struct sctp_chunk *sack;
> >>>  			asoc->a_rwnd = asoc->rwnd;
> >>>+
> >>>+			if (chunk->transport&&  !chunk->transport->moved_ctsn)
> >>>+				return retval;
> >>>+
> >>>  			sack = sctp_make_sack(asoc);
> >>>  			if (sack) {
> >>>  				retval = sctp_packet_append_chunk(pkt, sack);
> >>
> >>The new local variable 'trans' seems to be unused.
> >>
> >Crap, thank you Dave, that was a holdover from an initial pass I had made in
> >writing this.  I'll repost with that removed once Vald has a chance to look this
> >over
> >Neil
> >
> 
> Also, may want to move a_rwnd adjustment to after the new if clause.
> No sense adjusting it if we are just going to bail.
> 
> -vlad
> 

copy that, I'll make both changes and repost.  Thanks!
Neil


^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-26 20:31 ` Neil Horman
  (?)
  (?)
@ 2012-06-27 14:23 ` Neil Horman
  2012-06-27 15:10   ` Vlad Yasevich
  -1 siblings, 1 reply; 66+ messages in thread
From: Neil Horman @ 2012-06-27 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
---
 include/net/sctp/structs.h |    5 ++++-
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/output.c          |   10 +++++++---
 net/sctp/sm_make_chunk.c   |    7 +++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/tsnmap.c          |    5 ++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 8 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..712bf09 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -910,7 +910,10 @@ struct sctp_transport {
 		pmtu_pending:1,
 
 		/* Is this structure kfree()able? */
-		malloced:1;
+		malloced:1,
+
+		/* Has this transport moved the ctsn since we last sacked */
+		moved_ctsn:1;
 
 	struct flowi fl;
 
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..6c8cb9e 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,17 +240,21 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
-			asoc->a_rwnd = asoc->rwnd;
+
+			if (chunk->transport && !chunk->transport->moved_ctsn)
+				return retval;
+
 			sack = sctp_make_sack(asoc);
 			if (sack) {
+				asoc->a_rwnd = asoc->rwnd;
 				retval = sctp_packet_append_chunk(pkt, sack);
 				asoc->peer.sack_needed = 0;
 				if (del_timer(timer))
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..805babe 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	__u16 num_gabs, num_dup_tsns;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +806,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated, clear the moved_tsn information
+	 * from all the transports
+	 */
+	list_for_each_entry(trans, &asoc->peer.transport_addr_list, transports)
+		trans->moved_ctsn = 0;
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..619c638 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,8 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->moved_ctsn = 1;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-27 14:23 ` [PATCH v2] sctp: be more " Neil Horman
@ 2012-06-27 15:10   ` Vlad Yasevich
  2012-06-27 17:28     ` Neil Horman
  0 siblings, 1 reply; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-27 15:10 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller

On 06/27/2012 10:23 AM, Neil Horman wrote:
> It was noticed recently that when we send data on a transport, its possible that
> we might bundle a sack that arrived on a different transport.  While this isn't
> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> 2960:
>
>   An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>     etc.) to the same destination transport address from which it
>     received the DATA or control chunk to which it is replying.  This
>     rule should also be followed if the endpoint is bundling DATA chunks
>     together with the reply chunk.
>
> This patch seeks to correct that.  It restricts the bundling of sack operations
> to only those transports which have moved the ctsn of the association forward
> since the last sack.  By doing this we guarantee that we only bundle outbound
> saks on a transport that has received a chunk since the last sack.  This brings
> us into stricter compliance with the RFC.
>
> Vlad had initially suggested that we strictly allow only sack bundling on the
> transport that last moved the ctsn forward.  While this makes sense, I was
> concerned that doing so prevented us from bundling in the case where we had
> received chunks that moved the ctsn on multiple transports.  In those cases, the
> RFC allows us to select any of the transports having received chunks to bundle
> the sack on.  so I've modified the approach to allow for that, by adding a state
> variable to each transport that tracks weather it has moved the ctsn since the
> last sack.  This I think keeps our behavior (and performance), close enough to
> our current profile that I think we can do this without a sysctl knob to
> enable/disable it.
>
> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> CC: Vlad Yaseivch<vyasevich@gmail.com>
> CC: David S. Miller<davem@davemloft.net>
> Reported-by: Michele Baldessari<michele@redhat.com>
> Reported-by: sorin serban<sserban@redhat.com>
>
> ---
> Change Notes:
> V2)
> 	* Removed unused variable as per Dave M. Request
> 	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
> ---
>   include/net/sctp/structs.h |    5 ++++-
>   include/net/sctp/tsnmap.h  |    3 ++-
>   net/sctp/output.c          |   10 +++++++---
>   net/sctp/sm_make_chunk.c   |    7 +++++++
>   net/sctp/sm_sideeffect.c   |    2 +-
>   net/sctp/tsnmap.c          |    5 ++++-
>   net/sctp/ulpevent.c        |    3 ++-
>   net/sctp/ulpqueue.c        |    2 +-
>   8 files changed, 28 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index e4652fe..712bf09 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -910,7 +910,10 @@ struct sctp_transport {
>   		pmtu_pending:1,
>
>   		/* Is this structure kfree()able? */
> -		malloced:1;
> +		malloced:1,
> +
> +		/* Has this transport moved the ctsn since we last sacked */
> +		moved_ctsn:1;
>
>   	struct flowi fl;
>
> diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
> index e7728bc..2c5d2b4 100644
> --- a/include/net/sctp/tsnmap.h
> +++ b/include/net/sctp/tsnmap.h
> @@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
>   int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
> +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
> +		     struct sctp_transport *trans);
>
>   /* Mark this TSN and all lower as seen. */
>   void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
> diff --git a/net/sctp/output.c b/net/sctp/output.c
> index f1b7d4b..6c8cb9e 100644
> --- a/net/sctp/output.c
> +++ b/net/sctp/output.c
> @@ -240,17 +240,21 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>   	 */
>   	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
>   	!pkt->has_cookie_echo) {
> -		struct sctp_association *asoc;
>   		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +
>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>
>   		/* If the SACK timer is running, we have a pending SACK */
>   		if (timer_pending(timer)) {
>   			struct sctp_chunk *sack;
> -			asoc->a_rwnd = asoc->rwnd;
> +
> +			if (chunk->transport&&  !chunk->transport->moved_ctsn)
> +				return retval;
> +

I didn't think of this yesterday, but I think it would be much better to 
use pkt->transport here since you are adding the chunk to the packet and 
it will go out on the transport of the packet.  You are also guaranteed 
that pkt->transport is set.

>   			sack = sctp_make_sack(asoc);
>   			if (sack) {
> +				asoc->a_rwnd = asoc->rwnd;
>   				retval = sctp_packet_append_chunk(pkt, sack);
>   				asoc->peer.sack_needed = 0;
>   				if (del_timer(timer))
> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> index a85eeeb..805babe 100644
> --- a/net/sctp/sm_make_chunk.c
> +++ b/net/sctp/sm_make_chunk.c
> @@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   	__u16 num_gabs, num_dup_tsns;
>   	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
>   	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
> +	struct sctp_transport *trans;
>
>   	memset(gabs, 0, sizeof(gabs));
>   	ctsn = sctp_tsnmap_get_ctsn(map);
> @@ -805,6 +806,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
>   				 sctp_tsnmap_get_dups(map));
>
> +	/*
> +	 * Once we have a sack generated, clear the moved_tsn information
> +	 * from all the transports
> +	 */
> +	list_for_each_entry(trans,&asoc->peer.transport_addr_list, transports)
> +		trans->moved_ctsn = 0;
>   nodata:
>   	return retval;
>   }
> diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
> index c96d1a8..8716da1 100644
> --- a/net/sctp/sm_sideeffect.c
> +++ b/net/sctp/sm_sideeffect.c
> @@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
>   		case SCTP_CMD_REPORT_TSN:
>   			/* Record the arrival of a TSN.  */
>   			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -						 cmd->obj.u32);
> +						 cmd->obj.u32, NULL);
>   			break;
>
>   		case SCTP_CMD_REPORT_FWDTSN:
> diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
> index f1e40ceb..619c638 100644
> --- a/net/sctp/tsnmap.c
> +++ b/net/sctp/tsnmap.c
> @@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
>
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
> +int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
> +		     struct sctp_transport *trans)
>   {
>   	u16 gap;
>
> @@ -133,6 +134,8 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>   		 */
>   		map->max_tsn_seen++;
>   		map->cumulative_tsn_ack_point++;
> +		if (trans)
> +			trans->moved_ctsn = 1;
>   		map->base_tsn++;
>   	} else {
>   		/* Either we already have a gap, or about to record a gap, so
> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
> index 8a84017..33d8947 100644
> --- a/net/sctp/ulpevent.c
> +++ b/net/sctp/ulpevent.c
> @@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
>   	 * can mark it as received so the tsn_map is updated correctly.
>   	 */
>   	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -			     ntohl(chunk->subh.data_hdr->tsn)))
> +			     ntohl(chunk->subh.data_hdr->tsn),
> +			     chunk->transport))
>   		goto fail_mark;
>
>   	/* First calculate the padding, so we don't inadvertently
> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
> index f2d1de7..f5a6a4f 100644
> --- a/net/sctp/ulpqueue.c
> +++ b/net/sctp/ulpqueue.c
> @@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
>   	if (chunk&&  (freed>= needed)) {
>   		__u32 tsn;
>   		tsn = ntohl(chunk->subh.data_hdr->tsn);
> -		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
> +		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
>   		sctp_ulpq_tail_data(ulpq, chunk, gfp);
>
>   		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);

Also, I think you need to reset this bit in sctp_transport_reset(). 
Consider a potential association restart after SACKs have been received.

-vlad

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-27 15:10   ` Vlad Yasevich
@ 2012-06-27 17:28     ` Neil Horman
  2012-06-27 19:44         ` Vlad Yasevich
  0 siblings, 1 reply; 66+ messages in thread
From: Neil Horman @ 2012-06-27 17:28 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller

On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> On 06/27/2012 10:23 AM, Neil Horman wrote:
> >It was noticed recently that when we send data on a transport, its possible that
> >we might bundle a sack that arrived on a different transport.  While this isn't
> >a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> >2960:
> >
> >  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
> >    etc.) to the same destination transport address from which it
> >    received the DATA or control chunk to which it is replying.  This
> >    rule should also be followed if the endpoint is bundling DATA chunks
> >    together with the reply chunk.
> >
> >This patch seeks to correct that.  It restricts the bundling of sack operations
> >to only those transports which have moved the ctsn of the association forward
> >since the last sack.  By doing this we guarantee that we only bundle outbound
> >saks on a transport that has received a chunk since the last sack.  This brings
> >us into stricter compliance with the RFC.
> >
> >Vlad had initially suggested that we strictly allow only sack bundling on the
> >transport that last moved the ctsn forward.  While this makes sense, I was
> >concerned that doing so prevented us from bundling in the case where we had
> >received chunks that moved the ctsn on multiple transports.  In those cases, the
> >RFC allows us to select any of the transports having received chunks to bundle
> >the sack on.  so I've modified the approach to allow for that, by adding a state
> >variable to each transport that tracks weather it has moved the ctsn since the
> >last sack.  This I think keeps our behavior (and performance), close enough to
> >our current profile that I think we can do this without a sysctl knob to
> >enable/disable it.
> >
> >Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> >CC: Vlad Yaseivch<vyasevich@gmail.com>
> >CC: David S. Miller<davem@davemloft.net>
> >Reported-by: Michele Baldessari<michele@redhat.com>
> >Reported-by: sorin serban<sserban@redhat.com>
> >
> >---
> >Change Notes:
> >V2)
> >	* Removed unused variable as per Dave M. Request
> >	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
> >---
> >  include/net/sctp/structs.h |    5 ++++-
> >  include/net/sctp/tsnmap.h  |    3 ++-
> >  net/sctp/output.c          |   10 +++++++---
> >  net/sctp/sm_make_chunk.c   |    7 +++++++
> >  net/sctp/sm_sideeffect.c   |    2 +-
> >  net/sctp/tsnmap.c          |    5 ++++-
> >  net/sctp/ulpevent.c        |    3 ++-
> >  net/sctp/ulpqueue.c        |    2 +-
> >  8 files changed, 28 insertions(+), 9 deletions(-)
> >
> >diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> >index e4652fe..712bf09 100644
> >--- a/include/net/sctp/structs.h
> >+++ b/include/net/sctp/structs.h
> >@@ -910,7 +910,10 @@ struct sctp_transport {
> >  		pmtu_pending:1,
> >
> >  		/* Is this structure kfree()able? */
> >-		malloced:1;
> >+		malloced:1,
> >+
> >+		/* Has this transport moved the ctsn since we last sacked */
> >+		moved_ctsn:1;
> >
> >  	struct flowi fl;
> >
> >diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
> >index e7728bc..2c5d2b4 100644
> >--- a/include/net/sctp/tsnmap.h
> >+++ b/include/net/sctp/tsnmap.h
> >@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
> >  int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
> >
> >  /* Mark this TSN as seen.  */
> >-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
> >+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
> >+		     struct sctp_transport *trans);
> >
> >  /* Mark this TSN and all lower as seen. */
> >  void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
> >diff --git a/net/sctp/output.c b/net/sctp/output.c
> >index f1b7d4b..6c8cb9e 100644
> >--- a/net/sctp/output.c
> >+++ b/net/sctp/output.c
> >@@ -240,17 +240,21 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
> >  	 */
> >  	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
> >  	!pkt->has_cookie_echo) {
> >-		struct sctp_association *asoc;
> >  		struct timer_list *timer;
> >-		asoc = pkt->transport->asoc;
> >+		struct sctp_association *asoc = pkt->transport->asoc;
> >+
> >  		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
> >
> >  		/* If the SACK timer is running, we have a pending SACK */
> >  		if (timer_pending(timer)) {
> >  			struct sctp_chunk *sack;
> >-			asoc->a_rwnd = asoc->rwnd;
> >+
> >+			if (chunk->transport&&  !chunk->transport->moved_ctsn)
> >+				return retval;
> >+
> 
> I didn't think of this yesterday, but I think it would be much
> better to use pkt->transport here since you are adding the chunk to
> the packet and it will go out on the transport of the packet.  You
> are also guaranteed that pkt->transport is set.
> 
I don't think it really matters, as the chunk transport is used to lookup the
packet that we append to, and if the chunk transport is unset, its somewhat
questionable as to weather we should bundle, but if packet->transport is set,
its probably worth it to avoid the extra conditional.

> >  			sack = sctp_make_sack(asoc);
> >  			if (sack) {
> >+				asoc->a_rwnd = asoc->rwnd;
> >  				retval = sctp_packet_append_chunk(pkt, sack);
> >  				asoc->peer.sack_needed = 0;
> >  				if (del_timer(timer))
> >diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> >index a85eeeb..805babe 100644
> >--- a/net/sctp/sm_make_chunk.c
> >+++ b/net/sctp/sm_make_chunk.c
> >@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
> >  	__u16 num_gabs, num_dup_tsns;
> >  	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
> >  	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
> >+	struct sctp_transport *trans;
> >
> >  	memset(gabs, 0, sizeof(gabs));
> >  	ctsn = sctp_tsnmap_get_ctsn(map);
> >@@ -805,6 +806,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
> >  		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
> >  				 sctp_tsnmap_get_dups(map));
> >
> >+	/*
> >+	 * Once we have a sack generated, clear the moved_tsn information
> >+	 * from all the transports
> >+	 */
> >+	list_for_each_entry(trans,&asoc->peer.transport_addr_list, transports)
> >+		trans->moved_ctsn = 0;
> >  nodata:
> >  	return retval;
> >  }
> >diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
> >index c96d1a8..8716da1 100644
> >--- a/net/sctp/sm_sideeffect.c
> >+++ b/net/sctp/sm_sideeffect.c
> >@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
> >  		case SCTP_CMD_REPORT_TSN:
> >  			/* Record the arrival of a TSN.  */
> >  			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
> >-						 cmd->obj.u32);
> >+						 cmd->obj.u32, NULL);
> >  			break;
> >
> >  		case SCTP_CMD_REPORT_FWDTSN:
> >diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
> >index f1e40ceb..619c638 100644
> >--- a/net/sctp/tsnmap.c
> >+++ b/net/sctp/tsnmap.c
> >@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
> >
> >
> >  /* Mark this TSN as seen.  */
> >-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
> >+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
> >+		     struct sctp_transport *trans)
> >  {
> >  	u16 gap;
> >
> >@@ -133,6 +134,8 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
> >  		 */
> >  		map->max_tsn_seen++;
> >  		map->cumulative_tsn_ack_point++;
> >+		if (trans)
> >+			trans->moved_ctsn = 1;
> >  		map->base_tsn++;
> >  	} else {
> >  		/* Either we already have a gap, or about to record a gap, so
> >diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
> >index 8a84017..33d8947 100644
> >--- a/net/sctp/ulpevent.c
> >+++ b/net/sctp/ulpevent.c
> >@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
> >  	 * can mark it as received so the tsn_map is updated correctly.
> >  	 */
> >  	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
> >-			     ntohl(chunk->subh.data_hdr->tsn)))
> >+			     ntohl(chunk->subh.data_hdr->tsn),
> >+			     chunk->transport))
> >  		goto fail_mark;
> >
> >  	/* First calculate the padding, so we don't inadvertently
> >diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
> >index f2d1de7..f5a6a4f 100644
> >--- a/net/sctp/ulpqueue.c
> >+++ b/net/sctp/ulpqueue.c
> >@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
> >  	if (chunk&&  (freed>= needed)) {
> >  		__u32 tsn;
> >  		tsn = ntohl(chunk->subh.data_hdr->tsn);
> >-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
> >+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
> >  		sctp_ulpq_tail_data(ulpq, chunk, gfp);
> >
> >  		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
> 
> Also, I think you need to reset this bit in sctp_transport_reset().
> Consider a potential association restart after SACKs have been
> received.
> 
Yeah, thats true.  I'll add that in. 

Thanks!
Neil

> -vlad
> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-27 17:28     ` Neil Horman
@ 2012-06-27 19:44         ` Vlad Yasevich
  0 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-27 19:44 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/27/2012 01:28 PM, Neil Horman wrote:
> On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
>> On 06/27/2012 10:23 AM, Neil Horman wrote:
>>> It was noticed recently that when we send data on a transport, its possible that
>>> we might bundle a sack that arrived on a different transport.  While this isn't
>>> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
>>> 2960:
>>>
>>>   An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>>>     etc.) to the same destination transport address from which it
>>>     received the DATA or control chunk to which it is replying.  This
>>>     rule should also be followed if the endpoint is bundling DATA chunks
>>>     together with the reply chunk.
>>>
>>> This patch seeks to correct that.  It restricts the bundling of sack operations
>>> to only those transports which have moved the ctsn of the association forward
>>> since the last sack.  By doing this we guarantee that we only bundle outbound
>>> saks on a transport that has received a chunk since the last sack.  This brings
>>> us into stricter compliance with the RFC.
>>>
>>> Vlad had initially suggested that we strictly allow only sack bundling on the
>>> transport that last moved the ctsn forward.  While this makes sense, I was
>>> concerned that doing so prevented us from bundling in the case where we had
>>> received chunks that moved the ctsn on multiple transports.  In those cases, the
>>> RFC allows us to select any of the transports having received chunks to bundle
>>> the sack on.  so I've modified the approach to allow for that, by adding a state
>>> variable to each transport that tracks weather it has moved the ctsn since the
>>> last sack.  This I think keeps our behavior (and performance), close enough to
>>> our current profile that I think we can do this without a sysctl knob to
>>> enable/disable it.
>>>
>>> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
>>> CC: Vlad Yaseivch<vyasevich@gmail.com>
>>> CC: David S. Miller<davem@davemloft.net>
>>> Reported-by: Michele Baldessari<michele@redhat.com>
>>> Reported-by: sorin serban<sserban@redhat.com>
>>>
>>> ---
>>> Change Notes:
>>> V2)
>>> 	* Removed unused variable as per Dave M. Request
>>> 	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
>>> ---
>>>   include/net/sctp/structs.h |    5 ++++-
>>>   include/net/sctp/tsnmap.h  |    3 ++-
>>>   net/sctp/output.c          |   10 +++++++---
>>>   net/sctp/sm_make_chunk.c   |    7 +++++++
>>>   net/sctp/sm_sideeffect.c   |    2 +-
>>>   net/sctp/tsnmap.c          |    5 ++++-
>>>   net/sctp/ulpevent.c        |    3 ++-
>>>   net/sctp/ulpqueue.c        |    2 +-
>>>   8 files changed, 28 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
>>> index e4652fe..712bf09 100644
>>> --- a/include/net/sctp/structs.h
>>> +++ b/include/net/sctp/structs.h
>>> @@ -910,7 +910,10 @@ struct sctp_transport {
>>>   		pmtu_pending:1,
>>>
>>>   		/* Is this structure kfree()able? */
>>> -		malloced:1;
>>> +		malloced:1,
>>> +
>>> +		/* Has this transport moved the ctsn since we last sacked */
>>> +		moved_ctsn:1;
>>>
>>>   	struct flowi fl;
>>>
>>> diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
>>> index e7728bc..2c5d2b4 100644
>>> --- a/include/net/sctp/tsnmap.h
>>> +++ b/include/net/sctp/tsnmap.h
>>> @@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
>>>   int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
>>>
>>>   /* Mark this TSN as seen.  */
>>> -int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
>>> +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
>>> +		     struct sctp_transport *trans);
>>>
>>>   /* Mark this TSN and all lower as seen. */
>>>   void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
>>> diff --git a/net/sctp/output.c b/net/sctp/output.c
>>> index f1b7d4b..6c8cb9e 100644
>>> --- a/net/sctp/output.c
>>> +++ b/net/sctp/output.c
>>> @@ -240,17 +240,21 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>>>   	 */
>>>   	if (sctp_chunk_is_data(chunk)&&   !pkt->has_sack&&
>>>   	!pkt->has_cookie_echo) {
>>> -		struct sctp_association *asoc;
>>>   		struct timer_list *timer;
>>> -		asoc = pkt->transport->asoc;
>>> +		struct sctp_association *asoc = pkt->transport->asoc;
>>> +
>>>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>>>
>>>   		/* If the SACK timer is running, we have a pending SACK */
>>>   		if (timer_pending(timer)) {
>>>   			struct sctp_chunk *sack;
>>> -			asoc->a_rwnd = asoc->rwnd;
>>> +
>>> +			if (chunk->transport&&   !chunk->transport->moved_ctsn)
>>> +				return retval;
>>> +
>>
>> I didn't think of this yesterday, but I think it would be much
>> better to use pkt->transport here since you are adding the chunk to
>> the packet and it will go out on the transport of the packet.  You
>> are also guaranteed that pkt->transport is set.
>>
> I don't think it really matters, as the chunk transport is used to lookup the
> packet that we append to, and if the chunk transport is unset, its somewhat
> questionable as to weather we should bundle, but if packet->transport is set,
> its probably worth it to avoid the extra conditional.
>

Just looked at the code flow.  chunk->transport may not be set until the 
end of sctp_packet_append_chunk.  For new data, transport may not be 
set.  For retransmitted data, transport is set to last transport data 
was sent on.  So, we could be looking at the wrong transport.  What you 
are trying to decided is if the current transport we will be used can 
take the SACK, but you may not be looking at the current transport. 
Looking at packet->transport is the correct thing to do.

-vlad

>>>   			sack = sctp_make_sack(asoc);
>>>   			if (sack) {
>>> +				asoc->a_rwnd = asoc->rwnd;
>>>   				retval = sctp_packet_append_chunk(pkt, sack);
>>>   				asoc->peer.sack_needed = 0;
>>>   				if (del_timer(timer))
>>> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
>>> index a85eeeb..805babe 100644
>>> --- a/net/sctp/sm_make_chunk.c
>>> +++ b/net/sctp/sm_make_chunk.c
>>> @@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>>>   	__u16 num_gabs, num_dup_tsns;
>>>   	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
>>>   	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
>>> +	struct sctp_transport *trans;
>>>
>>>   	memset(gabs, 0, sizeof(gabs));
>>>   	ctsn = sctp_tsnmap_get_ctsn(map);
>>> @@ -805,6 +806,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>>>   		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
>>>   				 sctp_tsnmap_get_dups(map));
>>>
>>> +	/*
>>> +	 * Once we have a sack generated, clear the moved_tsn information
>>> +	 * from all the transports
>>> +	 */
>>> +	list_for_each_entry(trans,&asoc->peer.transport_addr_list, transports)
>>> +		trans->moved_ctsn = 0;
>>>   nodata:
>>>   	return retval;
>>>   }
>>> diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
>>> index c96d1a8..8716da1 100644
>>> --- a/net/sctp/sm_sideeffect.c
>>> +++ b/net/sctp/sm_sideeffect.c
>>> @@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
>>>   		case SCTP_CMD_REPORT_TSN:
>>>   			/* Record the arrival of a TSN.  */
>>>   			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
>>> -						 cmd->obj.u32);
>>> +						 cmd->obj.u32, NULL);
>>>   			break;
>>>
>>>   		case SCTP_CMD_REPORT_FWDTSN:
>>> diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
>>> index f1e40ceb..619c638 100644
>>> --- a/net/sctp/tsnmap.c
>>> +++ b/net/sctp/tsnmap.c
>>> @@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
>>>
>>>
>>>   /* Mark this TSN as seen.  */
>>> -int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>>> +int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
>>> +		     struct sctp_transport *trans)
>>>   {
>>>   	u16 gap;
>>>
>>> @@ -133,6 +134,8 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>>>   		 */
>>>   		map->max_tsn_seen++;
>>>   		map->cumulative_tsn_ack_point++;
>>> +		if (trans)
>>> +			trans->moved_ctsn = 1;
>>>   		map->base_tsn++;
>>>   	} else {
>>>   		/* Either we already have a gap, or about to record a gap, so
>>> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
>>> index 8a84017..33d8947 100644
>>> --- a/net/sctp/ulpevent.c
>>> +++ b/net/sctp/ulpevent.c
>>> @@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
>>>   	 * can mark it as received so the tsn_map is updated correctly.
>>>   	 */
>>>   	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
>>> -			     ntohl(chunk->subh.data_hdr->tsn)))
>>> +			     ntohl(chunk->subh.data_hdr->tsn),
>>> +			     chunk->transport))
>>>   		goto fail_mark;
>>>
>>>   	/* First calculate the padding, so we don't inadvertently
>>> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
>>> index f2d1de7..f5a6a4f 100644
>>> --- a/net/sctp/ulpqueue.c
>>> +++ b/net/sctp/ulpqueue.c
>>> @@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
>>>   	if (chunk&&   (freed>= needed)) {
>>>   		__u32 tsn;
>>>   		tsn = ntohl(chunk->subh.data_hdr->tsn);
>>> -		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
>>> +		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
>>>   		sctp_ulpq_tail_data(ulpq, chunk, gfp);
>>>
>>>   		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
>>
>> Also, I think you need to reset this bit in sctp_transport_reset().
>> Consider a potential association restart after SACKs have been
>> received.
>>
> Yeah, thats true.  I'll add that in.
>
> Thanks!
> Neil
>
>> -vlad
>>

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-27 19:44         ` Vlad Yasevich
  0 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-27 19:44 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/27/2012 01:28 PM, Neil Horman wrote:
> On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
>> On 06/27/2012 10:23 AM, Neil Horman wrote:
>>> It was noticed recently that when we send data on a transport, its possible that
>>> we might bundle a sack that arrived on a different transport.  While this isn't
>>> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
>>> 2960:
>>>
>>>   An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>>>     etc.) to the same destination transport address from which it
>>>     received the DATA or control chunk to which it is replying.  This
>>>     rule should also be followed if the endpoint is bundling DATA chunks
>>>     together with the reply chunk.
>>>
>>> This patch seeks to correct that.  It restricts the bundling of sack operations
>>> to only those transports which have moved the ctsn of the association forward
>>> since the last sack.  By doing this we guarantee that we only bundle outbound
>>> saks on a transport that has received a chunk since the last sack.  This brings
>>> us into stricter compliance with the RFC.
>>>
>>> Vlad had initially suggested that we strictly allow only sack bundling on the
>>> transport that last moved the ctsn forward.  While this makes sense, I was
>>> concerned that doing so prevented us from bundling in the case where we had
>>> received chunks that moved the ctsn on multiple transports.  In those cases, the
>>> RFC allows us to select any of the transports having received chunks to bundle
>>> the sack on.  so I've modified the approach to allow for that, by adding a state
>>> variable to each transport that tracks weather it has moved the ctsn since the
>>> last sack.  This I think keeps our behavior (and performance), close enough to
>>> our current profile that I think we can do this without a sysctl knob to
>>> enable/disable it.
>>>
>>> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
>>> CC: Vlad Yaseivch<vyasevich@gmail.com>
>>> CC: David S. Miller<davem@davemloft.net>
>>> Reported-by: Michele Baldessari<michele@redhat.com>
>>> Reported-by: sorin serban<sserban@redhat.com>
>>>
>>> ---
>>> Change Notes:
>>> V2)
>>> 	* Removed unused variable as per Dave M. Request
>>> 	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
>>> ---
>>>   include/net/sctp/structs.h |    5 ++++-
>>>   include/net/sctp/tsnmap.h  |    3 ++-
>>>   net/sctp/output.c          |   10 +++++++---
>>>   net/sctp/sm_make_chunk.c   |    7 +++++++
>>>   net/sctp/sm_sideeffect.c   |    2 +-
>>>   net/sctp/tsnmap.c          |    5 ++++-
>>>   net/sctp/ulpevent.c        |    3 ++-
>>>   net/sctp/ulpqueue.c        |    2 +-
>>>   8 files changed, 28 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
>>> index e4652fe..712bf09 100644
>>> --- a/include/net/sctp/structs.h
>>> +++ b/include/net/sctp/structs.h
>>> @@ -910,7 +910,10 @@ struct sctp_transport {
>>>   		pmtu_pending:1,
>>>
>>>   		/* Is this structure kfree()able? */
>>> -		malloced:1;
>>> +		malloced:1,
>>> +
>>> +		/* Has this transport moved the ctsn since we last sacked */
>>> +		moved_ctsn:1;
>>>
>>>   	struct flowi fl;
>>>
>>> diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
>>> index e7728bc..2c5d2b4 100644
>>> --- a/include/net/sctp/tsnmap.h
>>> +++ b/include/net/sctp/tsnmap.h
>>> @@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
>>>   int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
>>>
>>>   /* Mark this TSN as seen.  */
>>> -int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
>>> +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
>>> +		     struct sctp_transport *trans);
>>>
>>>   /* Mark this TSN and all lower as seen. */
>>>   void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
>>> diff --git a/net/sctp/output.c b/net/sctp/output.c
>>> index f1b7d4b..6c8cb9e 100644
>>> --- a/net/sctp/output.c
>>> +++ b/net/sctp/output.c
>>> @@ -240,17 +240,21 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>>>   	 */
>>>   	if (sctp_chunk_is_data(chunk)&&   !pkt->has_sack&&
>>>   	!pkt->has_cookie_echo) {
>>> -		struct sctp_association *asoc;
>>>   		struct timer_list *timer;
>>> -		asoc = pkt->transport->asoc;
>>> +		struct sctp_association *asoc = pkt->transport->asoc;
>>> +
>>>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>>>
>>>   		/* If the SACK timer is running, we have a pending SACK */
>>>   		if (timer_pending(timer)) {
>>>   			struct sctp_chunk *sack;
>>> -			asoc->a_rwnd = asoc->rwnd;
>>> +
>>> +			if (chunk->transport&&   !chunk->transport->moved_ctsn)
>>> +				return retval;
>>> +
>>
>> I didn't think of this yesterday, but I think it would be much
>> better to use pkt->transport here since you are adding the chunk to
>> the packet and it will go out on the transport of the packet.  You
>> are also guaranteed that pkt->transport is set.
>>
> I don't think it really matters, as the chunk transport is used to lookup the
> packet that we append to, and if the chunk transport is unset, its somewhat
> questionable as to weather we should bundle, but if packet->transport is set,
> its probably worth it to avoid the extra conditional.
>

Just looked at the code flow.  chunk->transport may not be set until the 
end of sctp_packet_append_chunk.  For new data, transport may not be 
set.  For retransmitted data, transport is set to last transport data 
was sent on.  So, we could be looking at the wrong transport.  What you 
are trying to decided is if the current transport we will be used can 
take the SACK, but you may not be looking at the current transport. 
Looking at packet->transport is the correct thing to do.

-vlad

>>>   			sack = sctp_make_sack(asoc);
>>>   			if (sack) {
>>> +				asoc->a_rwnd = asoc->rwnd;
>>>   				retval = sctp_packet_append_chunk(pkt, sack);
>>>   				asoc->peer.sack_needed = 0;
>>>   				if (del_timer(timer))
>>> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
>>> index a85eeeb..805babe 100644
>>> --- a/net/sctp/sm_make_chunk.c
>>> +++ b/net/sctp/sm_make_chunk.c
>>> @@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>>>   	__u16 num_gabs, num_dup_tsns;
>>>   	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
>>>   	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
>>> +	struct sctp_transport *trans;
>>>
>>>   	memset(gabs, 0, sizeof(gabs));
>>>   	ctsn = sctp_tsnmap_get_ctsn(map);
>>> @@ -805,6 +806,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>>>   		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
>>>   				 sctp_tsnmap_get_dups(map));
>>>
>>> +	/*
>>> +	 * Once we have a sack generated, clear the moved_tsn information
>>> +	 * from all the transports
>>> +	 */
>>> +	list_for_each_entry(trans,&asoc->peer.transport_addr_list, transports)
>>> +		trans->moved_ctsn = 0;
>>>   nodata:
>>>   	return retval;
>>>   }
>>> diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
>>> index c96d1a8..8716da1 100644
>>> --- a/net/sctp/sm_sideeffect.c
>>> +++ b/net/sctp/sm_sideeffect.c
>>> @@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
>>>   		case SCTP_CMD_REPORT_TSN:
>>>   			/* Record the arrival of a TSN.  */
>>>   			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
>>> -						 cmd->obj.u32);
>>> +						 cmd->obj.u32, NULL);
>>>   			break;
>>>
>>>   		case SCTP_CMD_REPORT_FWDTSN:
>>> diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
>>> index f1e40ceb..619c638 100644
>>> --- a/net/sctp/tsnmap.c
>>> +++ b/net/sctp/tsnmap.c
>>> @@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
>>>
>>>
>>>   /* Mark this TSN as seen.  */
>>> -int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>>> +int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
>>> +		     struct sctp_transport *trans)
>>>   {
>>>   	u16 gap;
>>>
>>> @@ -133,6 +134,8 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>>>   		 */
>>>   		map->max_tsn_seen++;
>>>   		map->cumulative_tsn_ack_point++;
>>> +		if (trans)
>>> +			trans->moved_ctsn = 1;
>>>   		map->base_tsn++;
>>>   	} else {
>>>   		/* Either we already have a gap, or about to record a gap, so
>>> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
>>> index 8a84017..33d8947 100644
>>> --- a/net/sctp/ulpevent.c
>>> +++ b/net/sctp/ulpevent.c
>>> @@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
>>>   	 * can mark it as received so the tsn_map is updated correctly.
>>>   	 */
>>>   	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
>>> -			     ntohl(chunk->subh.data_hdr->tsn)))
>>> +			     ntohl(chunk->subh.data_hdr->tsn),
>>> +			     chunk->transport))
>>>   		goto fail_mark;
>>>
>>>   	/* First calculate the padding, so we don't inadvertently
>>> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
>>> index f2d1de7..f5a6a4f 100644
>>> --- a/net/sctp/ulpqueue.c
>>> +++ b/net/sctp/ulpqueue.c
>>> @@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
>>>   	if (chunk&&   (freed>= needed)) {
>>>   		__u32 tsn;
>>>   		tsn = ntohl(chunk->subh.data_hdr->tsn);
>>> -		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
>>> +		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
>>>   		sctp_ulpq_tail_data(ulpq, chunk, gfp);
>>>
>>>   		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
>>
>> Also, I think you need to reset this bit in sctp_transport_reset().
>> Consider a potential association restart after SACKs have been
>> received.
>>
> Yeah, thats true.  I'll add that in.
>
> Thanks!
> Neil
>
>> -vlad
>>


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-27 19:44         ` Vlad Yasevich
@ 2012-06-28 15:33           ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 15:33 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> On 06/27/2012 01:28 PM, Neil Horman wrote:
> >On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>
> >>I didn't think of this yesterday, but I think it would be much
> >>better to use pkt->transport here since you are adding the chunk to
> >>the packet and it will go out on the transport of the packet.  You
> >>are also guaranteed that pkt->transport is set.
> >>
> >I don't think it really matters, as the chunk transport is used to lookup the
> >packet that we append to, and if the chunk transport is unset, its somewhat
> >questionable as to weather we should bundle, but if packet->transport is set,
> >its probably worth it to avoid the extra conditional.
> >
> 
> Just looked at the code flow.  chunk->transport may not be set until
> the end of sctp_packet_append_chunk.  For new data, transport may
> not be set.  For retransmitted data, transport is set to last
> transport data was sent on.  So, we could be looking at the wrong
> transport.  What you are trying to decided is if the current
> transport we will be used can take the SACK, but you may not be
> looking at the current transport. Looking at packet->transport is
> the correct thing to do.
> 
> -vlad
> 
So, I agree after what you said above, that this is the right thing to do.  That
said, I just tested the change with the SCTP_RR test in netperf, and it wound up
giving me horrid performance (Its reporting about 5 transactions per second).
It appears that whats happening is that, because the test alternates which
transports it sends out, and because it waits for a sack of teh prior packet
before it sends out the next transaction, we're always missing the bundle
opportunity, and always waiting for the 200ms timeout for the sack to occur.
While I know this is a pessimal case, it really seems bad to me.  It seems that
because I was using chunk->transport previously, I luckily got the transport
wrong sometimes, and it managed to bundle more often.

So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
here, but given that this is likely a corner cases, it seems that might be the
best approach.  Do you have any thoughts?

Neil

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-28 15:33           ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 15:33 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> On 06/27/2012 01:28 PM, Neil Horman wrote:
> >On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>
> >>I didn't think of this yesterday, but I think it would be much
> >>better to use pkt->transport here since you are adding the chunk to
> >>the packet and it will go out on the transport of the packet.  You
> >>are also guaranteed that pkt->transport is set.
> >>
> >I don't think it really matters, as the chunk transport is used to lookup the
> >packet that we append to, and if the chunk transport is unset, its somewhat
> >questionable as to weather we should bundle, but if packet->transport is set,
> >its probably worth it to avoid the extra conditional.
> >
> 
> Just looked at the code flow.  chunk->transport may not be set until
> the end of sctp_packet_append_chunk.  For new data, transport may
> not be set.  For retransmitted data, transport is set to last
> transport data was sent on.  So, we could be looking at the wrong
> transport.  What you are trying to decided is if the current
> transport we will be used can take the SACK, but you may not be
> looking at the current transport. Looking at packet->transport is
> the correct thing to do.
> 
> -vlad
> 
So, I agree after what you said above, that this is the right thing to do.  That
said, I just tested the change with the SCTP_RR test in netperf, and it wound up
giving me horrid performance (Its reporting about 5 transactions per second).
It appears that whats happening is that, because the test alternates which
transports it sends out, and because it waits for a sack of teh prior packet
before it sends out the next transaction, we're always missing the bundle
opportunity, and always waiting for the 200ms timeout for the sack to occur.
While I know this is a pessimal case, it really seems bad to me.  It seems that
because I was using chunk->transport previously, I luckily got the transport
wrong sometimes, and it managed to bundle more often.

So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
here, but given that this is likely a corner cases, it seems that might be the
best approach.  Do you have any thoughts?

Neil


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-28 15:33           ` Neil Horman
@ 2012-06-28 15:58             ` Vlad Yasevich
  -1 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-28 15:58 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/28/2012 11:33 AM, Neil Horman wrote:
> On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
>> On 06/27/2012 01:28 PM, Neil Horman wrote:
>>> On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
>>>>
>>>> I didn't think of this yesterday, but I think it would be much
>>>> better to use pkt->transport here since you are adding the chunk to
>>>> the packet and it will go out on the transport of the packet.  You
>>>> are also guaranteed that pkt->transport is set.
>>>>
>>> I don't think it really matters, as the chunk transport is used to lookup the
>>> packet that we append to, and if the chunk transport is unset, its somewhat
>>> questionable as to weather we should bundle, but if packet->transport is set,
>>> its probably worth it to avoid the extra conditional.
>>>
>>
>> Just looked at the code flow.  chunk->transport may not be set until
>> the end of sctp_packet_append_chunk.  For new data, transport may
>> not be set.  For retransmitted data, transport is set to last
>> transport data was sent on.  So, we could be looking at the wrong
>> transport.  What you are trying to decided is if the current
>> transport we will be used can take the SACK, but you may not be
>> looking at the current transport. Looking at packet->transport is
>> the correct thing to do.
>>
>> -vlad
>>
> So, I agree after what you said above, that this is the right thing to do.  That
> said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> giving me horrid performance (Its reporting about 5 transactions per second).
> It appears that whats happening is that, because the test alternates which
> transports it sends out, and because it waits for a sack of teh prior packet
> before it sends out the next transaction, we're always missing the bundle
> opportunity, and always waiting for the 200ms timeout for the sack to occur.
> While I know this is a pessimal case, it really seems bad to me.  It seems that
> because I was using chunk->transport previously, I luckily got the transport
> wrong sometimes, and it managed to bundle more often.
>
> So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> here, but given that this is likely a corner cases, it seems that might be the
> best approach.  Do you have any thoughts?
>
> Neil
>

that's strange.  did you modify the SCTP_RR to alternate transports? 
Seems like responses in the RR test need to go the address of the sender 
so that we don't see things like:
Request (t) --->
             <--- Response (t2)

Should be:
Request (t1) --->
              <--- Response (t1)


-vlad

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-28 15:58             ` Vlad Yasevich
  0 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-28 15:58 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/28/2012 11:33 AM, Neil Horman wrote:
> On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
>> On 06/27/2012 01:28 PM, Neil Horman wrote:
>>> On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
>>>>
>>>> I didn't think of this yesterday, but I think it would be much
>>>> better to use pkt->transport here since you are adding the chunk to
>>>> the packet and it will go out on the transport of the packet.  You
>>>> are also guaranteed that pkt->transport is set.
>>>>
>>> I don't think it really matters, as the chunk transport is used to lookup the
>>> packet that we append to, and if the chunk transport is unset, its somewhat
>>> questionable as to weather we should bundle, but if packet->transport is set,
>>> its probably worth it to avoid the extra conditional.
>>>
>>
>> Just looked at the code flow.  chunk->transport may not be set until
>> the end of sctp_packet_append_chunk.  For new data, transport may
>> not be set.  For retransmitted data, transport is set to last
>> transport data was sent on.  So, we could be looking at the wrong
>> transport.  What you are trying to decided is if the current
>> transport we will be used can take the SACK, but you may not be
>> looking at the current transport. Looking at packet->transport is
>> the correct thing to do.
>>
>> -vlad
>>
> So, I agree after what you said above, that this is the right thing to do.  That
> said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> giving me horrid performance (Its reporting about 5 transactions per second).
> It appears that whats happening is that, because the test alternates which
> transports it sends out, and because it waits for a sack of teh prior packet
> before it sends out the next transaction, we're always missing the bundle
> opportunity, and always waiting for the 200ms timeout for the sack to occur.
> While I know this is a pessimal case, it really seems bad to me.  It seems that
> because I was using chunk->transport previously, I luckily got the transport
> wrong sometimes, and it managed to bundle more often.
>
> So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> here, but given that this is likely a corner cases, it seems that might be the
> best approach.  Do you have any thoughts?
>
> Neil
>

that's strange.  did you modify the SCTP_RR to alternate transports? 
Seems like responses in the RR test need to go the address of the sender 
so that we don't see things like:
Request (t) --->
             <--- Response (t2)

Should be:
Request (t1) --->
              <--- Response (t1)


-vlad

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-28 15:58             ` Vlad Yasevich
@ 2012-06-28 18:07               ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 18:07 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
> On 06/28/2012 11:33 AM, Neil Horman wrote:
> >On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> >>On 06/27/2012 01:28 PM, Neil Horman wrote:
> >>>On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>>>
> >>>>I didn't think of this yesterday, but I think it would be much
> >>>>better to use pkt->transport here since you are adding the chunk to
> >>>>the packet and it will go out on the transport of the packet.  You
> >>>>are also guaranteed that pkt->transport is set.
> >>>>
> >>>I don't think it really matters, as the chunk transport is used to lookup the
> >>>packet that we append to, and if the chunk transport is unset, its somewhat
> >>>questionable as to weather we should bundle, but if packet->transport is set,
> >>>its probably worth it to avoid the extra conditional.
> >>>
> >>
> >>Just looked at the code flow.  chunk->transport may not be set until
> >>the end of sctp_packet_append_chunk.  For new data, transport may
> >>not be set.  For retransmitted data, transport is set to last
> >>transport data was sent on.  So, we could be looking at the wrong
> >>transport.  What you are trying to decided is if the current
> >>transport we will be used can take the SACK, but you may not be
> >>looking at the current transport. Looking at packet->transport is
> >>the correct thing to do.
> >>
> >>-vlad
> >>
> >So, I agree after what you said above, that this is the right thing to do.  That
> >said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> >giving me horrid performance (Its reporting about 5 transactions per second).
> >It appears that whats happening is that, because the test alternates which
> >transports it sends out, and because it waits for a sack of teh prior packet
> >before it sends out the next transaction, we're always missing the bundle
> >opportunity, and always waiting for the 200ms timeout for the sack to occur.
> >While I know this is a pessimal case, it really seems bad to me.  It seems that
> >because I was using chunk->transport previously, I luckily got the transport
> >wrong sometimes, and it managed to bundle more often.
> >
> >So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> >here, but given that this is likely a corner cases, it seems that might be the
> >best approach.  Do you have any thoughts?
> >
> >Neil
> >
> 
> that's strange.  did you modify the SCTP_RR to alternate transports?
> Seems like responses in the RR test need to go the address of the
> sender so that we don't see things like:
> Request (t) --->
>             <--- Response (t2)
> 
> Should be:
> Request (t1) --->
>              <--- Response (t1)
> 
> 
> -vlad
That would seem to me to be the case too....

However, having looked at this some more, it seems I just jumped the gun on
this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
command at the end of every received packet, which causes the moved_ctsn value
to get cleared.  We follow the sack every other packet rule instead of taking
the opportunity to bundle on send, so we're sending a packet with a sack, and a
second packet with a 1 byte data chunk (thats part of the SCTP_RR test).

I'm not sure why I didn't see this when I was using the chunk->transport
pointer.  Maybe I was just getting lucky with timing...

I'll see how I can go about fixing this.

Neil

> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-28 18:07               ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 18:07 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
> On 06/28/2012 11:33 AM, Neil Horman wrote:
> >On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> >>On 06/27/2012 01:28 PM, Neil Horman wrote:
> >>>On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>>>
> >>>>I didn't think of this yesterday, but I think it would be much
> >>>>better to use pkt->transport here since you are adding the chunk to
> >>>>the packet and it will go out on the transport of the packet.  You
> >>>>are also guaranteed that pkt->transport is set.
> >>>>
> >>>I don't think it really matters, as the chunk transport is used to lookup the
> >>>packet that we append to, and if the chunk transport is unset, its somewhat
> >>>questionable as to weather we should bundle, but if packet->transport is set,
> >>>its probably worth it to avoid the extra conditional.
> >>>
> >>
> >>Just looked at the code flow.  chunk->transport may not be set until
> >>the end of sctp_packet_append_chunk.  For new data, transport may
> >>not be set.  For retransmitted data, transport is set to last
> >>transport data was sent on.  So, we could be looking at the wrong
> >>transport.  What you are trying to decided is if the current
> >>transport we will be used can take the SACK, but you may not be
> >>looking at the current transport. Looking at packet->transport is
> >>the correct thing to do.
> >>
> >>-vlad
> >>
> >So, I agree after what you said above, that this is the right thing to do.  That
> >said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> >giving me horrid performance (Its reporting about 5 transactions per second).
> >It appears that whats happening is that, because the test alternates which
> >transports it sends out, and because it waits for a sack of teh prior packet
> >before it sends out the next transaction, we're always missing the bundle
> >opportunity, and always waiting for the 200ms timeout for the sack to occur.
> >While I know this is a pessimal case, it really seems bad to me.  It seems that
> >because I was using chunk->transport previously, I luckily got the transport
> >wrong sometimes, and it managed to bundle more often.
> >
> >So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> >here, but given that this is likely a corner cases, it seems that might be the
> >best approach.  Do you have any thoughts?
> >
> >Neil
> >
> 
> that's strange.  did you modify the SCTP_RR to alternate transports?
> Seems like responses in the RR test need to go the address of the
> sender so that we don't see things like:
> Request (t) --->
>             <--- Response (t2)
> 
> Should be:
> Request (t1) --->
>              <--- Response (t1)
> 
> 
> -vlad
That would seem to me to be the case too....

However, having looked at this some more, it seems I just jumped the gun on
this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
command at the end of every received packet, which causes the moved_ctsn value
to get cleared.  We follow the sack every other packet rule instead of taking
the opportunity to bundle on send, so we're sending a packet with a sack, and a
second packet with a 1 byte data chunk (thats part of the SCTP_RR test).

I'm not sure why I didn't see this when I was using the chunk->transport
pointer.  Maybe I was just getting lucky with timing...

I'll see how I can go about fixing this.

Neil

> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-28 18:07               ` Neil Horman
@ 2012-06-28 18:22                 ` Vlad Yasevich
  -1 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-28 18:22 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/28/2012 02:07 PM, Neil Horman wrote:
> On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
>> On 06/28/2012 11:33 AM, Neil Horman wrote:
>>> On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
>>>> On 06/27/2012 01:28 PM, Neil Horman wrote:
>>>>> On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
>>>>>>
>>>>>> I didn't think of this yesterday, but I think it would be much
>>>>>> better to use pkt->transport here since you are adding the chunk to
>>>>>> the packet and it will go out on the transport of the packet.  You
>>>>>> are also guaranteed that pkt->transport is set.
>>>>>>
>>>>> I don't think it really matters, as the chunk transport is used to lookup the
>>>>> packet that we append to, and if the chunk transport is unset, its somewhat
>>>>> questionable as to weather we should bundle, but if packet->transport is set,
>>>>> its probably worth it to avoid the extra conditional.
>>>>>
>>>>
>>>> Just looked at the code flow.  chunk->transport may not be set until
>>>> the end of sctp_packet_append_chunk.  For new data, transport may
>>>> not be set.  For retransmitted data, transport is set to last
>>>> transport data was sent on.  So, we could be looking at the wrong
>>>> transport.  What you are trying to decided is if the current
>>>> transport we will be used can take the SACK, but you may not be
>>>> looking at the current transport. Looking at packet->transport is
>>>> the correct thing to do.
>>>>
>>>> -vlad
>>>>
>>> So, I agree after what you said above, that this is the right thing to do.  That
>>> said, I just tested the change with the SCTP_RR test in netperf, and it wound up
>>> giving me horrid performance (Its reporting about 5 transactions per second).
>>> It appears that whats happening is that, because the test alternates which
>>> transports it sends out, and because it waits for a sack of teh prior packet
>>> before it sends out the next transaction, we're always missing the bundle
>>> opportunity, and always waiting for the 200ms timeout for the sack to occur.
>>> While I know this is a pessimal case, it really seems bad to me.  It seems that
>>> because I was using chunk->transport previously, I luckily got the transport
>>> wrong sometimes, and it managed to bundle more often.
>>>
>>> So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
>>> here, but given that this is likely a corner cases, it seems that might be the
>>> best approach.  Do you have any thoughts?
>>>
>>> Neil
>>>
>>
>> that's strange.  did you modify the SCTP_RR to alternate transports?
>> Seems like responses in the RR test need to go the address of the
>> sender so that we don't see things like:
>> Request (t) --->
>>              <--- Response (t2)
>>
>> Should be:
>> Request (t1) --->
>>               <--- Response (t1)
>>
>>
>> -vlad
> That would seem to me to be the case too....
>
> However, having looked at this some more, it seems I just jumped the gun on
> this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
> command at the end of every received packet, which causes the moved_ctsn value
> to get cleared.

Ok, that should only happen the very first time as we are supposed to 
ack the first data immediately.  On subsequent packets it should just 
start a timer because we are following the 2pkt/200ms rule.
Then, when the response happens, we should bundle the SACK as long as 
the data is leaving on the transport that moved the CTSN.

So we might be using the wrong transport and as result you send data and 
then end up waiting for a SACK.

-vlad

>  We follow the sack every other packet rule instead of taking
> the opportunity to bundle on send, so we're sending a packet with a sack, and a
> second packet with a 1 byte data chunk (thats part of the SCTP_RR test).
>
> I'm not sure why I didn't see this when I was using the chunk->transport
> pointer.  Maybe I was just getting lucky with timing...
>
> I'll see how I can go about fixing this.
>
> Neil
>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-28 18:22                 ` Vlad Yasevich
  0 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-28 18:22 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/28/2012 02:07 PM, Neil Horman wrote:
> On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
>> On 06/28/2012 11:33 AM, Neil Horman wrote:
>>> On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
>>>> On 06/27/2012 01:28 PM, Neil Horman wrote:
>>>>> On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
>>>>>>
>>>>>> I didn't think of this yesterday, but I think it would be much
>>>>>> better to use pkt->transport here since you are adding the chunk to
>>>>>> the packet and it will go out on the transport of the packet.  You
>>>>>> are also guaranteed that pkt->transport is set.
>>>>>>
>>>>> I don't think it really matters, as the chunk transport is used to lookup the
>>>>> packet that we append to, and if the chunk transport is unset, its somewhat
>>>>> questionable as to weather we should bundle, but if packet->transport is set,
>>>>> its probably worth it to avoid the extra conditional.
>>>>>
>>>>
>>>> Just looked at the code flow.  chunk->transport may not be set until
>>>> the end of sctp_packet_append_chunk.  For new data, transport may
>>>> not be set.  For retransmitted data, transport is set to last
>>>> transport data was sent on.  So, we could be looking at the wrong
>>>> transport.  What you are trying to decided is if the current
>>>> transport we will be used can take the SACK, but you may not be
>>>> looking at the current transport. Looking at packet->transport is
>>>> the correct thing to do.
>>>>
>>>> -vlad
>>>>
>>> So, I agree after what you said above, that this is the right thing to do.  That
>>> said, I just tested the change with the SCTP_RR test in netperf, and it wound up
>>> giving me horrid performance (Its reporting about 5 transactions per second).
>>> It appears that whats happening is that, because the test alternates which
>>> transports it sends out, and because it waits for a sack of teh prior packet
>>> before it sends out the next transaction, we're always missing the bundle
>>> opportunity, and always waiting for the 200ms timeout for the sack to occur.
>>> While I know this is a pessimal case, it really seems bad to me.  It seems that
>>> because I was using chunk->transport previously, I luckily got the transport
>>> wrong sometimes, and it managed to bundle more often.
>>>
>>> So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
>>> here, but given that this is likely a corner cases, it seems that might be the
>>> best approach.  Do you have any thoughts?
>>>
>>> Neil
>>>
>>
>> that's strange.  did you modify the SCTP_RR to alternate transports?
>> Seems like responses in the RR test need to go the address of the
>> sender so that we don't see things like:
>> Request (t) --->
>>              <--- Response (t2)
>>
>> Should be:
>> Request (t1) --->
>>               <--- Response (t1)
>>
>>
>> -vlad
> That would seem to me to be the case too....
>
> However, having looked at this some more, it seems I just jumped the gun on
> this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
> command at the end of every received packet, which causes the moved_ctsn value
> to get cleared.

Ok, that should only happen the very first time as we are supposed to 
ack the first data immediately.  On subsequent packets it should just 
start a timer because we are following the 2pkt/200ms rule.
Then, when the response happens, we should bundle the SACK as long as 
the data is leaving on the transport that moved the CTSN.

So we might be using the wrong transport and as result you send data and 
then end up waiting for a SACK.

-vlad

>  We follow the sack every other packet rule instead of taking
> the opportunity to bundle on send, so we're sending a packet with a sack, and a
> second packet with a 1 byte data chunk (thats part of the SCTP_RR test).
>
> I'm not sure why I didn't see this when I was using the chunk->transport
> pointer.  Maybe I was just getting lucky with timing...
>
> I'll see how I can go about fixing this.
>
> Neil
>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-28 18:22                 ` Vlad Yasevich
@ 2012-06-28 18:36                   ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 18:36 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Thu, Jun 28, 2012 at 02:22:07PM -0400, Vlad Yasevich wrote:
> On 06/28/2012 02:07 PM, Neil Horman wrote:
> >On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
> >>On 06/28/2012 11:33 AM, Neil Horman wrote:
> >>>On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> >>>>On 06/27/2012 01:28 PM, Neil Horman wrote:
> >>>>>On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>>>>>
> >>>>>>I didn't think of this yesterday, but I think it would be much
> >>>>>>better to use pkt->transport here since you are adding the chunk to
> >>>>>>the packet and it will go out on the transport of the packet.  You
> >>>>>>are also guaranteed that pkt->transport is set.
> >>>>>>
> >>>>>I don't think it really matters, as the chunk transport is used to lookup the
> >>>>>packet that we append to, and if the chunk transport is unset, its somewhat
> >>>>>questionable as to weather we should bundle, but if packet->transport is set,
> >>>>>its probably worth it to avoid the extra conditional.
> >>>>>
> >>>>
> >>>>Just looked at the code flow.  chunk->transport may not be set until
> >>>>the end of sctp_packet_append_chunk.  For new data, transport may
> >>>>not be set.  For retransmitted data, transport is set to last
> >>>>transport data was sent on.  So, we could be looking at the wrong
> >>>>transport.  What you are trying to decided is if the current
> >>>>transport we will be used can take the SACK, but you may not be
> >>>>looking at the current transport. Looking at packet->transport is
> >>>>the correct thing to do.
> >>>>
> >>>>-vlad
> >>>>
> >>>So, I agree after what you said above, that this is the right thing to do.  That
> >>>said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> >>>giving me horrid performance (Its reporting about 5 transactions per second).
> >>>It appears that whats happening is that, because the test alternates which
> >>>transports it sends out, and because it waits for a sack of teh prior packet
> >>>before it sends out the next transaction, we're always missing the bundle
> >>>opportunity, and always waiting for the 200ms timeout for the sack to occur.
> >>>While I know this is a pessimal case, it really seems bad to me.  It seems that
> >>>because I was using chunk->transport previously, I luckily got the transport
> >>>wrong sometimes, and it managed to bundle more often.
> >>>
> >>>So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> >>>here, but given that this is likely a corner cases, it seems that might be the
> >>>best approach.  Do you have any thoughts?
> >>>
> >>>Neil
> >>>
> >>
> >>that's strange.  did you modify the SCTP_RR to alternate transports?
> >>Seems like responses in the RR test need to go the address of the
> >>sender so that we don't see things like:
> >>Request (t) --->
> >>             <--- Response (t2)
> >>
> >>Should be:
> >>Request (t1) --->
> >>              <--- Response (t1)
> >>
> >>
> >>-vlad
> >That would seem to me to be the case too....
> >
> >However, having looked at this some more, it seems I just jumped the gun on
> >this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
> >command at the end of every received packet, which causes the moved_ctsn value
> >to get cleared.
> 
> Ok, that should only happen the very first time as we are supposed
> to ack the first data immediately.  On subsequent packets it should
> just start a timer because we are following the 2pkt/200ms rule.
> Then, when the response happens, we should bundle the SACK as long
> as the data is leaving on the transport that moved the CTSN.
> 
> So we might be using the wrong transport and as result you send data
> and then end up waiting for a SACK.
> 
Thats what I'm looking into now.  I'll let you know when I've figured it out
Neil

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-28 18:36                   ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 18:36 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Thu, Jun 28, 2012 at 02:22:07PM -0400, Vlad Yasevich wrote:
> On 06/28/2012 02:07 PM, Neil Horman wrote:
> >On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
> >>On 06/28/2012 11:33 AM, Neil Horman wrote:
> >>>On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> >>>>On 06/27/2012 01:28 PM, Neil Horman wrote:
> >>>>>On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>>>>>
> >>>>>>I didn't think of this yesterday, but I think it would be much
> >>>>>>better to use pkt->transport here since you are adding the chunk to
> >>>>>>the packet and it will go out on the transport of the packet.  You
> >>>>>>are also guaranteed that pkt->transport is set.
> >>>>>>
> >>>>>I don't think it really matters, as the chunk transport is used to lookup the
> >>>>>packet that we append to, and if the chunk transport is unset, its somewhat
> >>>>>questionable as to weather we should bundle, but if packet->transport is set,
> >>>>>its probably worth it to avoid the extra conditional.
> >>>>>
> >>>>
> >>>>Just looked at the code flow.  chunk->transport may not be set until
> >>>>the end of sctp_packet_append_chunk.  For new data, transport may
> >>>>not be set.  For retransmitted data, transport is set to last
> >>>>transport data was sent on.  So, we could be looking at the wrong
> >>>>transport.  What you are trying to decided is if the current
> >>>>transport we will be used can take the SACK, but you may not be
> >>>>looking at the current transport. Looking at packet->transport is
> >>>>the correct thing to do.
> >>>>
> >>>>-vlad
> >>>>
> >>>So, I agree after what you said above, that this is the right thing to do.  That
> >>>said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> >>>giving me horrid performance (Its reporting about 5 transactions per second).
> >>>It appears that whats happening is that, because the test alternates which
> >>>transports it sends out, and because it waits for a sack of teh prior packet
> >>>before it sends out the next transaction, we're always missing the bundle
> >>>opportunity, and always waiting for the 200ms timeout for the sack to occur.
> >>>While I know this is a pessimal case, it really seems bad to me.  It seems that
> >>>because I was using chunk->transport previously, I luckily got the transport
> >>>wrong sometimes, and it managed to bundle more often.
> >>>
> >>>So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> >>>here, but given that this is likely a corner cases, it seems that might be the
> >>>best approach.  Do you have any thoughts?
> >>>
> >>>Neil
> >>>
> >>
> >>that's strange.  did you modify the SCTP_RR to alternate transports?
> >>Seems like responses in the RR test need to go the address of the
> >>sender so that we don't see things like:
> >>Request (t) --->
> >>             <--- Response (t2)
> >>
> >>Should be:
> >>Request (t1) --->
> >>              <--- Response (t1)
> >>
> >>
> >>-vlad
> >That would seem to me to be the case too....
> >
> >However, having looked at this some more, it seems I just jumped the gun on
> >this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
> >command at the end of every received packet, which causes the moved_ctsn value
> >to get cleared.
> 
> Ok, that should only happen the very first time as we are supposed
> to ack the first data immediately.  On subsequent packets it should
> just start a timer because we are following the 2pkt/200ms rule.
> Then, when the response happens, we should bundle the SACK as long
> as the data is leaving on the transport that moved the CTSN.
> 
> So we might be using the wrong transport and as result you send data
> and then end up waiting for a SACK.
> 
Thats what I'm looking into now.  I'll let you know when I've figured it out
Neil


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-28 18:22                 ` Vlad Yasevich
@ 2012-06-28 20:14                   ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 20:14 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Thu, Jun 28, 2012 at 02:22:07PM -0400, Vlad Yasevich wrote:
> On 06/28/2012 02:07 PM, Neil Horman wrote:
> >On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
> >>On 06/28/2012 11:33 AM, Neil Horman wrote:
> >>>On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> >>>>On 06/27/2012 01:28 PM, Neil Horman wrote:
> >>>>>On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>>>>>
> >>>>>>I didn't think of this yesterday, but I think it would be much
> >>>>>>better to use pkt->transport here since you are adding the chunk to
> >>>>>>the packet and it will go out on the transport of the packet.  You
> >>>>>>are also guaranteed that pkt->transport is set.
> >>>>>>
> >>>>>I don't think it really matters, as the chunk transport is used to lookup the
> >>>>>packet that we append to, and if the chunk transport is unset, its somewhat
> >>>>>questionable as to weather we should bundle, but if packet->transport is set,
> >>>>>its probably worth it to avoid the extra conditional.
> >>>>>
> >>>>
> >>>>Just looked at the code flow.  chunk->transport may not be set until
> >>>>the end of sctp_packet_append_chunk.  For new data, transport may
> >>>>not be set.  For retransmitted data, transport is set to last
> >>>>transport data was sent on.  So, we could be looking at the wrong
> >>>>transport.  What you are trying to decided is if the current
> >>>>transport we will be used can take the SACK, but you may not be
> >>>>looking at the current transport. Looking at packet->transport is
> >>>>the correct thing to do.
> >>>>
> >>>>-vlad
> >>>>
> >>>So, I agree after what you said above, that this is the right thing to do.  That
> >>>said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> >>>giving me horrid performance (Its reporting about 5 transactions per second).
> >>>It appears that whats happening is that, because the test alternates which
> >>>transports it sends out, and because it waits for a sack of teh prior packet
> >>>before it sends out the next transaction, we're always missing the bundle
> >>>opportunity, and always waiting for the 200ms timeout for the sack to occur.
> >>>While I know this is a pessimal case, it really seems bad to me.  It seems that
> >>>because I was using chunk->transport previously, I luckily got the transport
> >>>wrong sometimes, and it managed to bundle more often.
> >>>
> >>>So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> >>>here, but given that this is likely a corner cases, it seems that might be the
> >>>best approach.  Do you have any thoughts?
> >>>
> >>>Neil
> >>>
> >>
> >>that's strange.  did you modify the SCTP_RR to alternate transports?
> >>Seems like responses in the RR test need to go the address of the
> >>sender so that we don't see things like:
> >>Request (t) --->
> >>             <--- Response (t2)
> >>
> >>Should be:
> >>Request (t1) --->
> >>              <--- Response (t1)
> >>
> >>
> >>-vlad
> >That would seem to me to be the case too....
> >
> >However, having looked at this some more, it seems I just jumped the gun on
> >this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
> >command at the end of every received packet, which causes the moved_ctsn value
> >to get cleared.
> 
> Ok, that should only happen the very first time as we are supposed
> to ack the first data immediately.  On subsequent packets it should
> just start a timer because we are following the 2pkt/200ms rule.
> Then, when the response happens, we should bundle the SACK as long
> as the data is leaving on the transport that moved the CTSN.
> 
> So we might be using the wrong transport and as result you send data
> and then end up waiting for a SACK.
> 

So, good news, and more good news - 

The good news is that I found the problem - and its me :)
When I modified the code to use pkt->transport over chunk->transport I removed
the ! in front of the test on accident, and and so was not bundling when I
should have been.  Quite stupid of me, sorry for the noise.

The other good news is that while doing this I think I have a way to save us
from having to do that for loop in sctp_make_sack, so this should be a bit more
scalable.  I'll post when I finish testing tomorrow.

Best
Neil

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-28 20:14                   ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-28 20:14 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller, linux-sctp

On Thu, Jun 28, 2012 at 02:22:07PM -0400, Vlad Yasevich wrote:
> On 06/28/2012 02:07 PM, Neil Horman wrote:
> >On Thu, Jun 28, 2012 at 11:58:56AM -0400, Vlad Yasevich wrote:
> >>On 06/28/2012 11:33 AM, Neil Horman wrote:
> >>>On Wed, Jun 27, 2012 at 03:44:22PM -0400, Vlad Yasevich wrote:
> >>>>On 06/27/2012 01:28 PM, Neil Horman wrote:
> >>>>>On Wed, Jun 27, 2012 at 11:10:26AM -0400, Vlad Yasevich wrote:
> >>>>>>
> >>>>>>I didn't think of this yesterday, but I think it would be much
> >>>>>>better to use pkt->transport here since you are adding the chunk to
> >>>>>>the packet and it will go out on the transport of the packet.  You
> >>>>>>are also guaranteed that pkt->transport is set.
> >>>>>>
> >>>>>I don't think it really matters, as the chunk transport is used to lookup the
> >>>>>packet that we append to, and if the chunk transport is unset, its somewhat
> >>>>>questionable as to weather we should bundle, but if packet->transport is set,
> >>>>>its probably worth it to avoid the extra conditional.
> >>>>>
> >>>>
> >>>>Just looked at the code flow.  chunk->transport may not be set until
> >>>>the end of sctp_packet_append_chunk.  For new data, transport may
> >>>>not be set.  For retransmitted data, transport is set to last
> >>>>transport data was sent on.  So, we could be looking at the wrong
> >>>>transport.  What you are trying to decided is if the current
> >>>>transport we will be used can take the SACK, but you may not be
> >>>>looking at the current transport. Looking at packet->transport is
> >>>>the correct thing to do.
> >>>>
> >>>>-vlad
> >>>>
> >>>So, I agree after what you said above, that this is the right thing to do.  That
> >>>said, I just tested the change with the SCTP_RR test in netperf, and it wound up
> >>>giving me horrid performance (Its reporting about 5 transactions per second).
> >>>It appears that whats happening is that, because the test alternates which
> >>>transports it sends out, and because it waits for a sack of teh prior packet
> >>>before it sends out the next transaction, we're always missing the bundle
> >>>opportunity, and always waiting for the 200ms timeout for the sack to occur.
> >>>While I know this is a pessimal case, it really seems bad to me.  It seems that
> >>>because I was using chunk->transport previously, I luckily got the transport
> >>>wrong sometimes, and it managed to bundle more often.
> >>>
> >>>So I'm not sure what to do here.  I had really wanted to avoid adding a sysctl
> >>>here, but given that this is likely a corner cases, it seems that might be the
> >>>best approach.  Do you have any thoughts?
> >>>
> >>>Neil
> >>>
> >>
> >>that's strange.  did you modify the SCTP_RR to alternate transports?
> >>Seems like responses in the RR test need to go the address of the
> >>sender so that we don't see things like:
> >>Request (t) --->
> >>             <--- Response (t2)
> >>
> >>Should be:
> >>Request (t1) --->
> >>              <--- Response (t1)
> >>
> >>
> >>-vlad
> >That would seem to me to be the case too....
> >
> >However, having looked at this some more, it seems I just jumped the gun on
> >this. Its happening because sctp_eat_data variants are issuing a SCTP_GEN_SACK
> >command at the end of every received packet, which causes the moved_ctsn value
> >to get cleared.
> 
> Ok, that should only happen the very first time as we are supposed
> to ack the first data immediately.  On subsequent packets it should
> just start a timer because we are following the 2pkt/200ms rule.
> Then, when the response happens, we should bundle the SACK as long
> as the data is leaving on the transport that moved the CTSN.
> 
> So we might be using the wrong transport and as result you send data
> and then end up waiting for a SACK.
> 

So, good news, and more good news - 

The good news is that I found the problem - and its me :)
When I modified the code to use pkt->transport over chunk->transport I removed
the ! in front of the test on accident, and and so was not bundling when I
should have been.  Quite stupid of me, sorry for the noise.

The other good news is that while doing this I think I have a way to save us
from having to do that for loop in sctp_make_sack, so this should be a bit more
scalable.  I'll post when I finish testing tomorrow.

Best
Neil


^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH v3] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-26 20:31 ` Neil Horman
                   ` (2 preceding siblings ...)
  (?)
@ 2012-06-29 16:34 ` Neil Horman
  2012-06-29 18:29   ` Vlad Yasevich
  -1 siblings, 1 reply; 66+ messages in thread
From: Neil Horman @ 2012-06-29 16:34 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
V3)
	* Switched test to use pkt->transport rather than chunk->transport
	* Modified detection of sacka-able transport.  Instead of just setting
	  and clearning a flag, we now mark each transport and association with
	  a sack generation tag.  We increment the associations generation on
	  every sack, and assign that generation tag to every transport that
	  updates the ctsn.  This prevents us from having to iterate over a for
	  loop on every sack, which is much more scalable.
---
 include/net/sctp/structs.h |    4 ++++
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/associola.c       |    1 +
 net/sctp/output.c          |    9 +++++++--
 net/sctp/sm_make_chunk.c   |   10 ++++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/transport.c       |    2 ++
 net/sctp/tsnmap.c          |    6 +++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 10 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..fecdf31 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -912,6 +912,9 @@ struct sctp_transport {
 		/* Is this structure kfree()able? */
 		malloced:1;
 
+	/* Has this transport moved the ctsn since we last sacked */
+	__u32 sack_generation;
+
 	struct flowi fl;
 
 	/* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
 		 */
 		__u8    sack_needed;     /* Do we need to sack the peer? */
 		__u32	sack_cnt;
+		__u32	sack_generation;
 
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable:1,	    /* Can peer do ECN? */
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5bc9ab1..6c66adb 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	 */
 	asoc->peer.sack_needed = 1;
 	asoc->peer.sack_cnt = 0;
+	asoc->peer.sack_generation=0;
 
 	/* Assume that the peer will tell us if he recognizes ASCONF
 	 * as part of INIT exchange.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..0de6cd5 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
+
+			if (pkt->transport->sack_generation !=
+			    pkt->transport->asoc->peer.sack_generation)
+				return retval;
+
 			asoc->a_rwnd = asoc->rwnd;
 			sack = sctp_make_sack(asoc);
 			if (sack) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..ffa2a8e 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	__u16 num_gabs, num_dup_tsns;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +806,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated, clear the moved_tsn information
+	 * from all the transports
+	 */
+	if (!asoc->peer.sack_generation)
+		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+				    transports)
+			trans->sack_generation = UINT_MAX;
+	((struct sctp_association *)asoc)->peer.sack_generation++;
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index b026ba0..1dcceb6 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
 	memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+	peer->sack_generation = 0;
+
 	/* From 6.3.1 RTO Calculation:
 	 *
 	 * C1) Until an RTT measurement has been made for a packet sent to the
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..b5fb7c4 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->sack_generation =
+				trans->asoc->peer.sack_generation;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH v3] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-29 16:34 ` [PATCH v3] " Neil Horman
@ 2012-06-29 18:29   ` Vlad Yasevich
  2012-06-29 18:43     ` Neil Horman
  0 siblings, 1 reply; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-29 18:29 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller

On 06/29/2012 12:34 PM, Neil Horman wrote:
> It was noticed recently that when we send data on a transport, its possible that
> we might bundle a sack that arrived on a different transport.  While this isn't
> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> 2960:
>
>   An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>     etc.) to the same destination transport address from which it
>     received the DATA or control chunk to which it is replying.  This
>     rule should also be followed if the endpoint is bundling DATA chunks
>     together with the reply chunk.
>
> This patch seeks to correct that.  It restricts the bundling of sack operations
> to only those transports which have moved the ctsn of the association forward
> since the last sack.  By doing this we guarantee that we only bundle outbound
> saks on a transport that has received a chunk since the last sack.  This brings
> us into stricter compliance with the RFC.
>
> Vlad had initially suggested that we strictly allow only sack bundling on the
> transport that last moved the ctsn forward.  While this makes sense, I was
> concerned that doing so prevented us from bundling in the case where we had
> received chunks that moved the ctsn on multiple transports.  In those cases, the
> RFC allows us to select any of the transports having received chunks to bundle
> the sack on.  so I've modified the approach to allow for that, by adding a state
> variable to each transport that tracks weather it has moved the ctsn since the
> last sack.  This I think keeps our behavior (and performance), close enough to
> our current profile that I think we can do this without a sysctl knob to
> enable/disable it.
>
> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> CC: Vlad Yaseivch<vyasevich@gmail.com>
> CC: David S. Miller<davem@davemloft.net>
> Reported-by: Michele Baldessari<michele@redhat.com>
> Reported-by: sorin serban<sserban@redhat.com>
>
> ---
> Change Notes:
> V2)
> 	* Removed unused variable as per Dave M. Request
> 	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
> V3)
> 	* Switched test to use pkt->transport rather than chunk->transport
> 	* Modified detection of sacka-able transport.  Instead of just setting
> 	  and clearning a flag, we now mark each transport and association with
> 	  a sack generation tag.  We increment the associations generation on
> 	  every sack, and assign that generation tag to every transport that
> 	  updates the ctsn.  This prevents us from having to iterate over a for
> 	  loop on every sack, which is much more scalable.
> ---
>   include/net/sctp/structs.h |    4 ++++
>   include/net/sctp/tsnmap.h  |    3 ++-
>   net/sctp/associola.c       |    1 +
>   net/sctp/output.c          |    9 +++++++--
>   net/sctp/sm_make_chunk.c   |   10 ++++++++++
>   net/sctp/sm_sideeffect.c   |    2 +-
>   net/sctp/transport.c       |    2 ++
>   net/sctp/tsnmap.c          |    6 +++++-
>   net/sctp/ulpevent.c        |    3 ++-
>   net/sctp/ulpqueue.c        |    2 +-
>   10 files changed, 35 insertions(+), 7 deletions(-)
>
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index e4652fe..fecdf31 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -912,6 +912,9 @@ struct sctp_transport {
>   		/* Is this structure kfree()able? */
>   		malloced:1;
>
> +	/* Has this transport moved the ctsn since we last sacked */
> +	__u32 sack_generation;
> +
>   	struct flowi fl;
>
>   	/* This is the peer's IP address and port. */
> @@ -1584,6 +1587,7 @@ struct sctp_association {
>   		 */
>   		__u8    sack_needed;     /* Do we need to sack the peer? */
>   		__u32	sack_cnt;
> +		__u32	sack_generation;
>
>   		/* These are capabilities which our peer advertised.  */
>   		__u8	ecn_capable:1,	    /* Can peer do ECN? */
> diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
> index e7728bc..2c5d2b4 100644
> --- a/include/net/sctp/tsnmap.h
> +++ b/include/net/sctp/tsnmap.h
> @@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
>   int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
> +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
> +		     struct sctp_transport *trans);
>
>   /* Mark this TSN and all lower as seen. */
>   void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 5bc9ab1..6c66adb 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
>   	 */
>   	asoc->peer.sack_needed = 1;
>   	asoc->peer.sack_cnt = 0;
> +	asoc->peer.sack_generation=0;
>
>   	/* Assume that the peer will tell us if he recognizes ASCONF
>   	 * as part of INIT exchange.
> diff --git a/net/sctp/output.c b/net/sctp/output.c
> index f1b7d4b..0de6cd5 100644
> --- a/net/sctp/output.c
> +++ b/net/sctp/output.c
> @@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>   	 */
>   	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
>   	!pkt->has_cookie_echo) {
> -		struct sctp_association *asoc;
>   		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +
>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>
>   		/* If the SACK timer is running, we have a pending SACK */
>   		if (timer_pending(timer)) {
>   			struct sctp_chunk *sack;
> +
> +			if (pkt->transport->sack_generation !=
> +			    pkt->transport->asoc->peer.sack_generation)
> +				return retval;
> +
>   			asoc->a_rwnd = asoc->rwnd;
>   			sack = sctp_make_sack(asoc);
>   			if (sack) {
> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> index a85eeeb..ffa2a8e 100644
> --- a/net/sctp/sm_make_chunk.c
> +++ b/net/sctp/sm_make_chunk.c
> @@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   	__u16 num_gabs, num_dup_tsns;
>   	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
>   	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
> +	struct sctp_transport *trans;
>
>   	memset(gabs, 0, sizeof(gabs));
>   	ctsn = sctp_tsnmap_get_ctsn(map);
> @@ -805,6 +806,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
>   				 sctp_tsnmap_get_dups(map));
>
> +	/*
> +	 * Once we have a sack generated, clear the moved_tsn information
> +	 * from all the transports
> +	 */
> +	if (!asoc->peer.sack_generation)
> +		list_for_each_entry(trans,&asoc->peer.transport_addr_list,
> +				    transports)
> +			trans->sack_generation = UINT_MAX;
> +	((struct sctp_association *)asoc)->peer.sack_generation++;

Two points here:
1) The commend no longer matches the code
2) Why special case the peer.sack_generations == 0 and set the transport 
to UNIT_MAX?

-vlad

>   nodata:
>   	return retval;
>   }
> diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
> index c96d1a8..8716da1 100644
> --- a/net/sctp/sm_sideeffect.c
> +++ b/net/sctp/sm_sideeffect.c
> @@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
>   		case SCTP_CMD_REPORT_TSN:
>   			/* Record the arrival of a TSN.  */
>   			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -						 cmd->obj.u32);
> +						 cmd->obj.u32, NULL);
>   			break;
>
>   		case SCTP_CMD_REPORT_FWDTSN:
> diff --git a/net/sctp/transport.c b/net/sctp/transport.c
> index b026ba0..1dcceb6 100644
> --- a/net/sctp/transport.c
> +++ b/net/sctp/transport.c
> @@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
>   	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
>   	memset(&peer->saddr, 0, sizeof(union sctp_addr));
>
> +	peer->sack_generation = 0;
> +
>   	/* From 6.3.1 RTO Calculation:
>   	 *
>   	 * C1) Until an RTT measurement has been made for a packet sent to the
> diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
> index f1e40ceb..b5fb7c4 100644
> --- a/net/sctp/tsnmap.c
> +++ b/net/sctp/tsnmap.c
> @@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
>
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
> +int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
> +		     struct sctp_transport *trans)
>   {
>   	u16 gap;
>
> @@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>   		 */
>   		map->max_tsn_seen++;
>   		map->cumulative_tsn_ack_point++;
> +		if (trans)
> +			trans->sack_generation =
> +				trans->asoc->peer.sack_generation;
>   		map->base_tsn++;
>   	} else {
>   		/* Either we already have a gap, or about to record a gap, so
> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
> index 8a84017..33d8947 100644
> --- a/net/sctp/ulpevent.c
> +++ b/net/sctp/ulpevent.c
> @@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
>   	 * can mark it as received so the tsn_map is updated correctly.
>   	 */
>   	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -			     ntohl(chunk->subh.data_hdr->tsn)))
> +			     ntohl(chunk->subh.data_hdr->tsn),
> +			     chunk->transport))
>   		goto fail_mark;
>
>   	/* First calculate the padding, so we don't inadvertently
> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
> index f2d1de7..f5a6a4f 100644
> --- a/net/sctp/ulpqueue.c
> +++ b/net/sctp/ulpqueue.c
> @@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
>   	if (chunk&&  (freed>= needed)) {
>   		__u32 tsn;
>   		tsn = ntohl(chunk->subh.data_hdr->tsn);
> -		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
> +		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
>   		sctp_ulpq_tail_data(ulpq, chunk, gfp);
>
>   		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v3] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-29 18:29   ` Vlad Yasevich
@ 2012-06-29 18:43     ` Neil Horman
  2012-06-29 19:15       ` Vlad Yasevich
  0 siblings, 1 reply; 66+ messages in thread
From: Neil Horman @ 2012-06-29 18:43 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller

On Fri, Jun 29, 2012 at 02:29:52PM -0400, Vlad Yasevich wrote:
> On 06/29/2012 12:34 PM, Neil Horman wrote:
> >It was noticed recently that when we send data on a transport, its possible that
> >we might bundle a sack that arrived on a different transport.  While this isn't
> >a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> >2960:
> >
> >  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
> >    etc.) to the same destination transport address from which it
> >    received the DATA or control chunk to which it is replying.  This
> >    rule should also be followed if the endpoint is bundling DATA chunks
> >    together with the reply chunk.
> >
> >This patch seeks to correct that.  It restricts the bundling of sack operations
> >to only those transports which have moved the ctsn of the association forward
> >since the last sack.  By doing this we guarantee that we only bundle outbound
> >saks on a transport that has received a chunk since the last sack.  This brings
> >us into stricter compliance with the RFC.
> >
> >Vlad had initially suggested that we strictly allow only sack bundling on the
> >transport that last moved the ctsn forward.  While this makes sense, I was
> >concerned that doing so prevented us from bundling in the case where we had
> >received chunks that moved the ctsn on multiple transports.  In those cases, the
> >RFC allows us to select any of the transports having received chunks to bundle
> >the sack on.  so I've modified the approach to allow for that, by adding a state
> >variable to each transport that tracks weather it has moved the ctsn since the
> >last sack.  This I think keeps our behavior (and performance), close enough to
> >our current profile that I think we can do this without a sysctl knob to
> >enable/disable it.
> >
> >Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> >CC: Vlad Yaseivch<vyasevich@gmail.com>
> >CC: David S. Miller<davem@davemloft.net>
> >Reported-by: Michele Baldessari<michele@redhat.com>
> >Reported-by: sorin serban<sserban@redhat.com>
> >
> >---
> >Change Notes:
> >V2)
> >	* Removed unused variable as per Dave M. Request
> >	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
> >V3)
> >	* Switched test to use pkt->transport rather than chunk->transport
> >	* Modified detection of sacka-able transport.  Instead of just setting
> >	  and clearning a flag, we now mark each transport and association with
> >	  a sack generation tag.  We increment the associations generation on
> >	  every sack, and assign that generation tag to every transport that
> >	  updates the ctsn.  This prevents us from having to iterate over a for
> >	  loop on every sack, which is much more scalable.
> >---
> >  include/net/sctp/structs.h |    4 ++++
> >  include/net/sctp/tsnmap.h  |    3 ++-
> >  net/sctp/associola.c       |    1 +
> >  net/sctp/output.c          |    9 +++++++--
> >  net/sctp/sm_make_chunk.c   |   10 ++++++++++
> >  net/sctp/sm_sideeffect.c   |    2 +-
> >  net/sctp/transport.c       |    2 ++
> >  net/sctp/tsnmap.c          |    6 +++++-
> >  net/sctp/ulpevent.c        |    3 ++-
> >  net/sctp/ulpqueue.c        |    2 +-
> >  10 files changed, 35 insertions(+), 7 deletions(-)
> >
> >diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> >index e4652fe..fecdf31 100644
> >--- a/include/net/sctp/structs.h
> >+++ b/include/net/sctp/structs.h
> >@@ -912,6 +912,9 @@ struct sctp_transport {
> >  		/* Is this structure kfree()able? */
> >  		malloced:1;
> >
> >+	/* Has this transport moved the ctsn since we last sacked */
> >+	__u32 sack_generation;
> >+
> >  	struct flowi fl;
> >
> >  	/* This is the peer's IP address and port. */
> >@@ -1584,6 +1587,7 @@ struct sctp_association {
> >  		 */
> >  		__u8    sack_needed;     /* Do we need to sack the peer? */
> >  		__u32	sack_cnt;
> >+		__u32	sack_generation;
> >
> >  		/* These are capabilities which our peer advertised.  */
> >  		__u8	ecn_capable:1,	    /* Can peer do ECN? */
> >diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
> >index e7728bc..2c5d2b4 100644
> >--- a/include/net/sctp/tsnmap.h
> >+++ b/include/net/sctp/tsnmap.h
> >@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
> >  int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
> >
> >  /* Mark this TSN as seen.  */
> >-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
> >+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
> >+		     struct sctp_transport *trans);
> >
> >  /* Mark this TSN and all lower as seen. */
> >  void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
> >diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> >index 5bc9ab1..6c66adb 100644
> >--- a/net/sctp/associola.c
> >+++ b/net/sctp/associola.c
> >@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
> >  	 */
> >  	asoc->peer.sack_needed = 1;
> >  	asoc->peer.sack_cnt = 0;
> >+	asoc->peer.sack_generation=0;
> >
> >  	/* Assume that the peer will tell us if he recognizes ASCONF
> >  	 * as part of INIT exchange.
> >diff --git a/net/sctp/output.c b/net/sctp/output.c
> >index f1b7d4b..0de6cd5 100644
> >--- a/net/sctp/output.c
> >+++ b/net/sctp/output.c
> >@@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
> >  	 */
> >  	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
> >  	!pkt->has_cookie_echo) {
> >-		struct sctp_association *asoc;
> >  		struct timer_list *timer;
> >-		asoc = pkt->transport->asoc;
> >+		struct sctp_association *asoc = pkt->transport->asoc;
> >+
> >  		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
> >
> >  		/* If the SACK timer is running, we have a pending SACK */
> >  		if (timer_pending(timer)) {
> >  			struct sctp_chunk *sack;
> >+
> >+			if (pkt->transport->sack_generation !=
> >+			    pkt->transport->asoc->peer.sack_generation)
> >+				return retval;
> >+
> >  			asoc->a_rwnd = asoc->rwnd;
> >  			sack = sctp_make_sack(asoc);
> >  			if (sack) {
> >diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> >index a85eeeb..ffa2a8e 100644
> >--- a/net/sctp/sm_make_chunk.c
> >+++ b/net/sctp/sm_make_chunk.c
> >@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
> >  	__u16 num_gabs, num_dup_tsns;
> >  	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
> >  	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
> >+	struct sctp_transport *trans;
> >
> >  	memset(gabs, 0, sizeof(gabs));
> >  	ctsn = sctp_tsnmap_get_ctsn(map);
> >@@ -805,6 +806,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
> >  		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
> >  				 sctp_tsnmap_get_dups(map));
> >
> >+	/*
> >+	 * Once we have a sack generated, clear the moved_tsn information
> >+	 * from all the transports
> >+	 */
> >+	if (!asoc->peer.sack_generation)
> >+		list_for_each_entry(trans,&asoc->peer.transport_addr_list,
> >+				    transports)
> >+			trans->sack_generation = UINT_MAX;
> >+	((struct sctp_association *)asoc)->peer.sack_generation++;
> 
> Two points here:
> 1) The commend no longer matches the code
Crud, missed that, I'll fix it.

> 2) Why special case the peer.sack_generations == 0 and set the
> transport to UNIT_MAX?
> 
To avoid wrapping problems leading to erroneous bundling errors.  Consider a
long lived connection with two trasports (A and B).

If all traffic is sent on A for a long time (generating UINT_MAX sacks), and the
peer chooses that moment to send data on transport B, its possible that we will
bundle a sack with that data chunk erroneously, because the associations
sack_generation has wrapped, and now matches with the transports, even though we
never received data on transport B.  The special casing ensures that we never
hit that problem.

Neil

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v3] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-29 18:43     ` Neil Horman
@ 2012-06-29 19:15       ` Vlad Yasevich
  2012-06-29 19:21         ` Neil Horman
  0 siblings, 1 reply; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-29 19:15 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller

On 06/29/2012 02:43 PM, Neil Horman wrote:
> On Fri, Jun 29, 2012 at 02:29:52PM -0400, Vlad Yasevich wrote:
>> On 06/29/2012 12:34 PM, Neil Horman wrote:
>>> It was noticed recently that when we send data on a transport, its possible that
>>> we might bundle a sack that arrived on a different transport.  While this isn't
>>> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
>>> 2960:
>>>
>>>   An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>>>     etc.) to the same destination transport address from which it
>>>     received the DATA or control chunk to which it is replying.  This
>>>     rule should also be followed if the endpoint is bundling DATA chunks
>>>     together with the reply chunk.
>>>
>>> This patch seeks to correct that.  It restricts the bundling of sack operations
>>> to only those transports which have moved the ctsn of the association forward
>>> since the last sack.  By doing this we guarantee that we only bundle outbound
>>> saks on a transport that has received a chunk since the last sack.  This brings
>>> us into stricter compliance with the RFC.
>>>
>>> Vlad had initially suggested that we strictly allow only sack bundling on the
>>> transport that last moved the ctsn forward.  While this makes sense, I was
>>> concerned that doing so prevented us from bundling in the case where we had
>>> received chunks that moved the ctsn on multiple transports.  In those cases, the
>>> RFC allows us to select any of the transports having received chunks to bundle
>>> the sack on.  so I've modified the approach to allow for that, by adding a state
>>> variable to each transport that tracks weather it has moved the ctsn since the
>>> last sack.  This I think keeps our behavior (and performance), close enough to
>>> our current profile that I think we can do this without a sysctl knob to
>>> enable/disable it.
>>>
>>> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
>>> CC: Vlad Yaseivch<vyasevich@gmail.com>
>>> CC: David S. Miller<davem@davemloft.net>
>>> Reported-by: Michele Baldessari<michele@redhat.com>
>>> Reported-by: sorin serban<sserban@redhat.com>
>>>
>>> ---
>>> Change Notes:
>>> V2)
>>> 	* Removed unused variable as per Dave M. Request
>>> 	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
>>> V3)
>>> 	* Switched test to use pkt->transport rather than chunk->transport
>>> 	* Modified detection of sacka-able transport.  Instead of just setting
>>> 	  and clearning a flag, we now mark each transport and association with
>>> 	  a sack generation tag.  We increment the associations generation on
>>> 	  every sack, and assign that generation tag to every transport that
>>> 	  updates the ctsn.  This prevents us from having to iterate over a for
>>> 	  loop on every sack, which is much more scalable.
>>> ---
>>>   include/net/sctp/structs.h |    4 ++++
>>>   include/net/sctp/tsnmap.h  |    3 ++-
>>>   net/sctp/associola.c       |    1 +
>>>   net/sctp/output.c          |    9 +++++++--
>>>   net/sctp/sm_make_chunk.c   |   10 ++++++++++
>>>   net/sctp/sm_sideeffect.c   |    2 +-
>>>   net/sctp/transport.c       |    2 ++
>>>   net/sctp/tsnmap.c          |    6 +++++-
>>>   net/sctp/ulpevent.c        |    3 ++-
>>>   net/sctp/ulpqueue.c        |    2 +-
>>>   10 files changed, 35 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
>>> index e4652fe..fecdf31 100644
>>> --- a/include/net/sctp/structs.h
>>> +++ b/include/net/sctp/structs.h
>>> @@ -912,6 +912,9 @@ struct sctp_transport {
>>>   		/* Is this structure kfree()able? */
>>>   		malloced:1;
>>>
>>> +	/* Has this transport moved the ctsn since we last sacked */
>>> +	__u32 sack_generation;
>>> +
>>>   	struct flowi fl;
>>>
>>>   	/* This is the peer's IP address and port. */
>>> @@ -1584,6 +1587,7 @@ struct sctp_association {
>>>   		 */
>>>   		__u8    sack_needed;     /* Do we need to sack the peer? */
>>>   		__u32	sack_cnt;
>>> +		__u32	sack_generation;
>>>
>>>   		/* These are capabilities which our peer advertised.  */
>>>   		__u8	ecn_capable:1,	    /* Can peer do ECN? */
>>> diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
>>> index e7728bc..2c5d2b4 100644
>>> --- a/include/net/sctp/tsnmap.h
>>> +++ b/include/net/sctp/tsnmap.h
>>> @@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
>>>   int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
>>>
>>>   /* Mark this TSN as seen.  */
>>> -int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
>>> +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
>>> +		     struct sctp_transport *trans);
>>>
>>>   /* Mark this TSN and all lower as seen. */
>>>   void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
>>> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
>>> index 5bc9ab1..6c66adb 100644
>>> --- a/net/sctp/associola.c
>>> +++ b/net/sctp/associola.c
>>> @@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
>>>   	 */
>>>   	asoc->peer.sack_needed = 1;
>>>   	asoc->peer.sack_cnt = 0;
>>> +	asoc->peer.sack_generation=0;
>>>
>>>   	/* Assume that the peer will tell us if he recognizes ASCONF
>>>   	 * as part of INIT exchange.
>>> diff --git a/net/sctp/output.c b/net/sctp/output.c
>>> index f1b7d4b..0de6cd5 100644
>>> --- a/net/sctp/output.c
>>> +++ b/net/sctp/output.c
>>> @@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>>>   	 */
>>>   	if (sctp_chunk_is_data(chunk)&&   !pkt->has_sack&&
>>>   	!pkt->has_cookie_echo) {
>>> -		struct sctp_association *asoc;
>>>   		struct timer_list *timer;
>>> -		asoc = pkt->transport->asoc;
>>> +		struct sctp_association *asoc = pkt->transport->asoc;
>>> +
>>>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>>>
>>>   		/* If the SACK timer is running, we have a pending SACK */
>>>   		if (timer_pending(timer)) {
>>>   			struct sctp_chunk *sack;
>>> +
>>> +			if (pkt->transport->sack_generation !=
>>> +			    pkt->transport->asoc->peer.sack_generation)
>>> +				return retval;
>>> +
>>>   			asoc->a_rwnd = asoc->rwnd;
>>>   			sack = sctp_make_sack(asoc);
>>>   			if (sack) {
>>> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
>>> index a85eeeb..ffa2a8e 100644
>>> --- a/net/sctp/sm_make_chunk.c
>>> +++ b/net/sctp/sm_make_chunk.c
>>> @@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>>>   	__u16 num_gabs, num_dup_tsns;
>>>   	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
>>>   	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
>>> +	struct sctp_transport *trans;
>>>
>>>   	memset(gabs, 0, sizeof(gabs));
>>>   	ctsn = sctp_tsnmap_get_ctsn(map);
>>> @@ -805,6 +806,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>>>   		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
>>>   				 sctp_tsnmap_get_dups(map));
>>>
>>> +	/*
>>> +	 * Once we have a sack generated, clear the moved_tsn information
>>> +	 * from all the transports
>>> +	 */
>>> +	if (!asoc->peer.sack_generation)
>>> +		list_for_each_entry(trans,&asoc->peer.transport_addr_list,
>>> +				    transports)
>>> +			trans->sack_generation = UINT_MAX;
>>> +	((struct sctp_association *)asoc)->peer.sack_generation++;
>>
>> Two points here:
>> 1) The commend no longer matches the code
> Crud, missed that, I'll fix it.
>
>> 2) Why special case the peer.sack_generations == 0 and set the
>> transport to UNIT_MAX?
>>
> To avoid wrapping problems leading to erroneous bundling errors.  Consider a
> long lived connection with two trasports (A and B).
>
> If all traffic is sent on A for a long time (generating UINT_MAX sacks), and the
> peer chooses that moment to send data on transport B, its possible that we will
> bundle a sack with that data chunk erroneously, because the associations
> sack_generation has wrapped, and now matches with the transports, even though we
> never received data on transport B.  The special casing ensures that we never
> hit that problem.
>

But you just move this condition to the UINT_MAX value instead.  If we 
use the alternate transport at the time that sack_generation == 
UINT_MAX, we may pick the wrong transport.

You may want to consider value 0 reserved as UNUSED and make 
peer.sack_generation start at 1 and wrap to 1.

-vlad

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v3] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-29 19:15       ` Vlad Yasevich
@ 2012-06-29 19:21         ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-29 19:21 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, David S. Miller

On Fri, Jun 29, 2012 at 03:15:12PM -0400, Vlad Yasevich wrote:
> On 06/29/2012 02:43 PM, Neil Horman wrote:
> >On Fri, Jun 29, 2012 at 02:29:52PM -0400, Vlad Yasevich wrote:
> >>On 06/29/2012 12:34 PM, Neil Horman wrote:
> >>>It was noticed recently that when we send data on a transport, its possible that
> >>>we might bundle a sack that arrived on a different transport.  While this isn't
> >>>a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> >>>2960:
> >>>
> >>>  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
> >>>    etc.) to the same destination transport address from which it
> >>>    received the DATA or control chunk to which it is replying.  This
> >>>    rule should also be followed if the endpoint is bundling DATA chunks
> >>>    together with the reply chunk.
> >>>
> >>>This patch seeks to correct that.  It restricts the bundling of sack operations
> >>>to only those transports which have moved the ctsn of the association forward
> >>>since the last sack.  By doing this we guarantee that we only bundle outbound
> >>>saks on a transport that has received a chunk since the last sack.  This brings
> >>>us into stricter compliance with the RFC.
> >>>
> >>>Vlad had initially suggested that we strictly allow only sack bundling on the
> >>>transport that last moved the ctsn forward.  While this makes sense, I was
> >>>concerned that doing so prevented us from bundling in the case where we had
> >>>received chunks that moved the ctsn on multiple transports.  In those cases, the
> >>>RFC allows us to select any of the transports having received chunks to bundle
> >>>the sack on.  so I've modified the approach to allow for that, by adding a state
> >>>variable to each transport that tracks weather it has moved the ctsn since the
> >>>last sack.  This I think keeps our behavior (and performance), close enough to
> >>>our current profile that I think we can do this without a sysctl knob to
> >>>enable/disable it.
> >>>
> >>>Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> >>>CC: Vlad Yaseivch<vyasevich@gmail.com>
> >>>CC: David S. Miller<davem@davemloft.net>
> >>>Reported-by: Michele Baldessari<michele@redhat.com>
> >>>Reported-by: sorin serban<sserban@redhat.com>
> >>>
> >>>---
> >>>Change Notes:
> >>>V2)
> >>>	* Removed unused variable as per Dave M. Request
> >>>	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
> >>>V3)
> >>>	* Switched test to use pkt->transport rather than chunk->transport
> >>>	* Modified detection of sacka-able transport.  Instead of just setting
> >>>	  and clearning a flag, we now mark each transport and association with
> >>>	  a sack generation tag.  We increment the associations generation on
> >>>	  every sack, and assign that generation tag to every transport that
> >>>	  updates the ctsn.  This prevents us from having to iterate over a for
> >>>	  loop on every sack, which is much more scalable.
> >>>---
> >>>  include/net/sctp/structs.h |    4 ++++
> >>>  include/net/sctp/tsnmap.h  |    3 ++-
> >>>  net/sctp/associola.c       |    1 +
> >>>  net/sctp/output.c          |    9 +++++++--
> >>>  net/sctp/sm_make_chunk.c   |   10 ++++++++++
> >>>  net/sctp/sm_sideeffect.c   |    2 +-
> >>>  net/sctp/transport.c       |    2 ++
> >>>  net/sctp/tsnmap.c          |    6 +++++-
> >>>  net/sctp/ulpevent.c        |    3 ++-
> >>>  net/sctp/ulpqueue.c        |    2 +-
> >>>  10 files changed, 35 insertions(+), 7 deletions(-)
> >>>
> >>>diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> >>>index e4652fe..fecdf31 100644
> >>>--- a/include/net/sctp/structs.h
> >>>+++ b/include/net/sctp/structs.h
> >>>@@ -912,6 +912,9 @@ struct sctp_transport {
> >>>  		/* Is this structure kfree()able? */
> >>>  		malloced:1;
> >>>
> >>>+	/* Has this transport moved the ctsn since we last sacked */
> >>>+	__u32 sack_generation;
> >>>+
> >>>  	struct flowi fl;
> >>>
> >>>  	/* This is the peer's IP address and port. */
> >>>@@ -1584,6 +1587,7 @@ struct sctp_association {
> >>>  		 */
> >>>  		__u8    sack_needed;     /* Do we need to sack the peer? */
> >>>  		__u32	sack_cnt;
> >>>+		__u32	sack_generation;
> >>>
> >>>  		/* These are capabilities which our peer advertised.  */
> >>>  		__u8	ecn_capable:1,	    /* Can peer do ECN? */
> >>>diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
> >>>index e7728bc..2c5d2b4 100644
> >>>--- a/include/net/sctp/tsnmap.h
> >>>+++ b/include/net/sctp/tsnmap.h
> >>>@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
> >>>  int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
> >>>
> >>>  /* Mark this TSN as seen.  */
> >>>-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
> >>>+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
> >>>+		     struct sctp_transport *trans);
> >>>
> >>>  /* Mark this TSN and all lower as seen. */
> >>>  void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
> >>>diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> >>>index 5bc9ab1..6c66adb 100644
> >>>--- a/net/sctp/associola.c
> >>>+++ b/net/sctp/associola.c
> >>>@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
> >>>  	 */
> >>>  	asoc->peer.sack_needed = 1;
> >>>  	asoc->peer.sack_cnt = 0;
> >>>+	asoc->peer.sack_generation=0;
> >>>
> >>>  	/* Assume that the peer will tell us if he recognizes ASCONF
> >>>  	 * as part of INIT exchange.
> >>>diff --git a/net/sctp/output.c b/net/sctp/output.c
> >>>index f1b7d4b..0de6cd5 100644
> >>>--- a/net/sctp/output.c
> >>>+++ b/net/sctp/output.c
> >>>@@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
> >>>  	 */
> >>>  	if (sctp_chunk_is_data(chunk)&&   !pkt->has_sack&&
> >>>  	!pkt->has_cookie_echo) {
> >>>-		struct sctp_association *asoc;
> >>>  		struct timer_list *timer;
> >>>-		asoc = pkt->transport->asoc;
> >>>+		struct sctp_association *asoc = pkt->transport->asoc;
> >>>+
> >>>  		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
> >>>
> >>>  		/* If the SACK timer is running, we have a pending SACK */
> >>>  		if (timer_pending(timer)) {
> >>>  			struct sctp_chunk *sack;
> >>>+
> >>>+			if (pkt->transport->sack_generation !=
> >>>+			    pkt->transport->asoc->peer.sack_generation)
> >>>+				return retval;
> >>>+
> >>>  			asoc->a_rwnd = asoc->rwnd;
> >>>  			sack = sctp_make_sack(asoc);
> >>>  			if (sack) {
> >>>diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> >>>index a85eeeb..ffa2a8e 100644
> >>>--- a/net/sctp/sm_make_chunk.c
> >>>+++ b/net/sctp/sm_make_chunk.c
> >>>@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
> >>>  	__u16 num_gabs, num_dup_tsns;
> >>>  	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
> >>>  	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
> >>>+	struct sctp_transport *trans;
> >>>
> >>>  	memset(gabs, 0, sizeof(gabs));
> >>>  	ctsn = sctp_tsnmap_get_ctsn(map);
> >>>@@ -805,6 +806,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
> >>>  		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
> >>>  				 sctp_tsnmap_get_dups(map));
> >>>
> >>>+	/*
> >>>+	 * Once we have a sack generated, clear the moved_tsn information
> >>>+	 * from all the transports
> >>>+	 */
> >>>+	if (!asoc->peer.sack_generation)
> >>>+		list_for_each_entry(trans,&asoc->peer.transport_addr_list,
> >>>+				    transports)
> >>>+			trans->sack_generation = UINT_MAX;
> >>>+	((struct sctp_association *)asoc)->peer.sack_generation++;
> >>
> >>Two points here:
> >>1) The commend no longer matches the code
> >Crud, missed that, I'll fix it.
> >
> >>2) Why special case the peer.sack_generations == 0 and set the
> >>transport to UNIT_MAX?
> >>
> >To avoid wrapping problems leading to erroneous bundling errors.  Consider a
> >long lived connection with two trasports (A and B).
> >
> >If all traffic is sent on A for a long time (generating UINT_MAX sacks), and the
> >peer chooses that moment to send data on transport B, its possible that we will
> >bundle a sack with that data chunk erroneously, because the associations
> >sack_generation has wrapped, and now matches with the transports, even though we
> >never received data on transport B.  The special casing ensures that we never
> >hit that problem.
> >
> 
> But you just move this condition to the UINT_MAX value instead.  If
> we use the alternate transport at the time that sack_generation ==
> UINT_MAX, we may pick the wrong transport.
> 
Yes, i noticed that as I was fixing the comment, thank you!

> You may want to consider value 0 reserved as UNUSED and make
> peer.sack_generation start at 1 and wrap to 1.
> 
Thats exactly what I just did :)
Neil

> -vlad
> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH v4] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-26 20:31 ` Neil Horman
@ 2012-06-29 19:24   ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-29 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
V3)
	* Switched test to use pkt->transport rather than chunk->transport
	* Modified detection of sacka-able transport.  Instead of just setting
	  and clearning a flag, we now mark each transport and association with
	  a sack generation tag.  We increment the associations generation on
	  every sack, and assign that generation tag to every transport that
	  updates the ctsn.  This prevents us from having to iterate over a for
	  loop on every sack, which is much more scalable.
V4)
	* Fixed up wrapping comment and logic
---
 include/net/sctp/structs.h |    4 ++++
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/associola.c       |    1 +
 net/sctp/output.c          |    9 +++++++--
 net/sctp/sm_make_chunk.c   |   18 ++++++++++++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/transport.c       |    2 ++
 net/sctp/tsnmap.c          |    6 +++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 10 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..fecdf31 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -912,6 +912,9 @@ struct sctp_transport {
 		/* Is this structure kfree()able? */
 		malloced:1;
 
+	/* Has this transport moved the ctsn since we last sacked */
+	__u32 sack_generation;
+
 	struct flowi fl;
 
 	/* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
 		 */
 		__u8    sack_needed;     /* Do we need to sack the peer? */
 		__u32	sack_cnt;
+		__u32	sack_generation;
 
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable:1,	    /* Can peer do ECN? */
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5bc9ab1..b16517e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	 */
 	asoc->peer.sack_needed = 1;
 	asoc->peer.sack_cnt = 0;
+	asoc->peer.sack_generation = 1;
 
 	/* Assume that the peer will tell us if he recognizes ASCONF
 	 * as part of INIT exchange.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..0de6cd5 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
+
+			if (pkt->transport->sack_generation !=
+			    pkt->transport->asoc->peer.sack_generation)
+				return retval;
+
 			asoc->a_rwnd = asoc->rwnd;
 			sack = sctp_make_sack(asoc);
 			if (sack) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..ae587d4 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	__u16 num_gabs, num_dup_tsns;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +806,23 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated:
+	 * 1) Check to see what our sack generation is, if its UINT_MAX, reset
+	 *    the transports to 1, and wrap the association generation back to
+	 *    zero
+	 * 2) Increment out sack_generation
+	 * The idea is that zero is never used as a valid generation for the
+	 * association so no transport will match after a wrap event like this,
+	 * Until the next sack
+	 */ 
+	if (asoc->peer.sack_generation == UINT_MAX) {
+		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+				    transports)
+			trans->sack_generation = 0;
+		((struct sctp_association *)asoc)->peer.sack_generation = 0;
+	}
+	((struct sctp_association *)asoc)->peer.sack_generation++;
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index b026ba0..1dcceb6 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
 	memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+	peer->sack_generation = 0;
+
 	/* From 6.3.1 RTO Calculation:
 	 *
 	 * C1) Until an RTT measurement has been made for a packet sent to the
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..b5fb7c4 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->sack_generation =
+				trans->asoc->peer.sack_generation;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH v4] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-29 19:24   ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-29 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
V3)
	* Switched test to use pkt->transport rather than chunk->transport
	* Modified detection of sacka-able transport.  Instead of just setting
	  and clearning a flag, we now mark each transport and association with
	  a sack generation tag.  We increment the associations generation on
	  every sack, and assign that generation tag to every transport that
	  updates the ctsn.  This prevents us from having to iterate over a for
	  loop on every sack, which is much more scalable.
V4)
	* Fixed up wrapping comment and logic
---
 include/net/sctp/structs.h |    4 ++++
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/associola.c       |    1 +
 net/sctp/output.c          |    9 +++++++--
 net/sctp/sm_make_chunk.c   |   18 ++++++++++++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/transport.c       |    2 ++
 net/sctp/tsnmap.c          |    6 +++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 10 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..fecdf31 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -912,6 +912,9 @@ struct sctp_transport {
 		/* Is this structure kfree()able? */
 		malloced:1;
 
+	/* Has this transport moved the ctsn since we last sacked */
+	__u32 sack_generation;
+
 	struct flowi fl;
 
 	/* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
 		 */
 		__u8    sack_needed;     /* Do we need to sack the peer? */
 		__u32	sack_cnt;
+		__u32	sack_generation;
 
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable:1,	    /* Can peer do ECN? */
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5bc9ab1..b16517e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	 */
 	asoc->peer.sack_needed = 1;
 	asoc->peer.sack_cnt = 0;
+	asoc->peer.sack_generation = 1;
 
 	/* Assume that the peer will tell us if he recognizes ASCONF
 	 * as part of INIT exchange.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..0de6cd5 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
+
+			if (pkt->transport->sack_generation !+			    pkt->transport->asoc->peer.sack_generation)
+				return retval;
+
 			asoc->a_rwnd = asoc->rwnd;
 			sack = sctp_make_sack(asoc);
 			if (sack) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..ae587d4 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -736,6 +736,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	__u16 num_gabs, num_dup_tsns;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +806,23 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated:
+	 * 1) Check to see what our sack generation is, if its UINT_MAX, reset
+	 *    the transports to 1, and wrap the association generation back to
+	 *    zero
+	 * 2) Increment out sack_generation
+	 * The idea is that zero is never used as a valid generation for the
+	 * association so no transport will match after a wrap event like this,
+	 * Until the next sack
+	 */ 
+	if (asoc->peer.sack_generation = UINT_MAX) {
+		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+				    transports)
+			trans->sack_generation = 0;
+		((struct sctp_association *)asoc)->peer.sack_generation = 0;
+	}
+	((struct sctp_association *)asoc)->peer.sack_generation++;
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index b026ba0..1dcceb6 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
 	memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+	peer->sack_generation = 0;
+
 	/* From 6.3.1 RTO Calculation:
 	 *
 	 * C1) Until an RTT measurement has been made for a packet sent to the
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..b5fb7c4 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->sack_generation +				trans->asoc->peer.sack_generation;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-26 20:31 ` Neil Horman
@ 2012-06-29 20:15   ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-29 20:15 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
V3)
	* Switched test to use pkt->transport rather than chunk->transport
	* Modified detection of sacka-able transport.  Instead of just setting
	  and clearning a flag, we now mark each transport and association with
	  a sack generation tag.  We increment the associations generation on
	  every sack, and assign that generation tag to every transport that
	  updates the ctsn.  This prevents us from having to iterate over a for
	  loop on every sack, which is much more scalable.
V4)
	* Fixed up wrapping comment and logic
V5)
	* Simplified wrap logic further per request from vlad
---
 include/net/sctp/structs.h |    4 ++++
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/associola.c       |    1 +
 net/sctp/output.c          |    9 +++++++--
 net/sctp/sm_make_chunk.c   |   17 +++++++++++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/transport.c       |    2 ++
 net/sctp/tsnmap.c          |    6 +++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 10 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..fecdf31 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -912,6 +912,9 @@ struct sctp_transport {
 		/* Is this structure kfree()able? */
 		malloced:1;
 
+	/* Has this transport moved the ctsn since we last sacked */
+	__u32 sack_generation;
+
 	struct flowi fl;
 
 	/* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
 		 */
 		__u8    sack_needed;     /* Do we need to sack the peer? */
 		__u32	sack_cnt;
+		__u32	sack_generation;
 
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable:1,	    /* Can peer do ECN? */
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5bc9ab1..b16517e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	 */
 	asoc->peer.sack_needed = 1;
 	asoc->peer.sack_cnt = 0;
+	asoc->peer.sack_generation = 1;
 
 	/* Assume that the peer will tell us if he recognizes ASCONF
 	 * as part of INIT exchange.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..0de6cd5 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
+
+			if (pkt->transport->sack_generation !=
+			    pkt->transport->asoc->peer.sack_generation)
+				return retval;
+
 			asoc->a_rwnd = asoc->rwnd;
 			sack = sctp_make_sack(asoc);
 			if (sack) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..6486cac 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -734,8 +734,10 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	int len;
 	__u32 ctsn;
 	__u16 num_gabs, num_dup_tsns;
+	struct sctp_association *aptr = (struct sctp_association *)asoc;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +807,21 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated, check to see what our sack
+	 * generation is, if its 0, reset the transports to 0, and reset
+	 * the association generation to 1
+	 *
+	 * The idea is that zero is never used as a valid generation for the
+	 * association so no transport will match after a wrap event like this,
+	 * Until the next sack
+	 */ 
+	if (++aptr->peer.sack_generation == 0) {
+		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+				    transports)
+			trans->sack_generation = 0;
+		aptr->peer.sack_generation = 1;
+	}
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index b026ba0..1dcceb6 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
 	memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+	peer->sack_generation = 0;
+
 	/* From 6.3.1 RTO Calculation:
 	 *
 	 * C1) Until an RTT measurement has been made for a packet sent to the
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..b5fb7c4 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->sack_generation =
+				trans->asoc->peer.sack_generation;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-29 20:15   ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-29 20:15 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
V3)
	* Switched test to use pkt->transport rather than chunk->transport
	* Modified detection of sacka-able transport.  Instead of just setting
	  and clearning a flag, we now mark each transport and association with
	  a sack generation tag.  We increment the associations generation on
	  every sack, and assign that generation tag to every transport that
	  updates the ctsn.  This prevents us from having to iterate over a for
	  loop on every sack, which is much more scalable.
V4)
	* Fixed up wrapping comment and logic
V5)
	* Simplified wrap logic further per request from vlad
---
 include/net/sctp/structs.h |    4 ++++
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/associola.c       |    1 +
 net/sctp/output.c          |    9 +++++++--
 net/sctp/sm_make_chunk.c   |   17 +++++++++++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/transport.c       |    2 ++
 net/sctp/tsnmap.c          |    6 +++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 10 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..fecdf31 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -912,6 +912,9 @@ struct sctp_transport {
 		/* Is this structure kfree()able? */
 		malloced:1;
 
+	/* Has this transport moved the ctsn since we last sacked */
+	__u32 sack_generation;
+
 	struct flowi fl;
 
 	/* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
 		 */
 		__u8    sack_needed;     /* Do we need to sack the peer? */
 		__u32	sack_cnt;
+		__u32	sack_generation;
 
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable:1,	    /* Can peer do ECN? */
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5bc9ab1..b16517e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	 */
 	asoc->peer.sack_needed = 1;
 	asoc->peer.sack_cnt = 0;
+	asoc->peer.sack_generation = 1;
 
 	/* Assume that the peer will tell us if he recognizes ASCONF
 	 * as part of INIT exchange.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..0de6cd5 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 	 */
 	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
-		struct sctp_association *asoc;
 		struct timer_list *timer;
-		asoc = pkt->transport->asoc;
+		struct sctp_association *asoc = pkt->transport->asoc;
+
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
+
+			if (pkt->transport->sack_generation !+			    pkt->transport->asoc->peer.sack_generation)
+				return retval;
+
 			asoc->a_rwnd = asoc->rwnd;
 			sack = sctp_make_sack(asoc);
 			if (sack) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..6486cac 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -734,8 +734,10 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	int len;
 	__u32 ctsn;
 	__u16 num_gabs, num_dup_tsns;
+	struct sctp_association *aptr = (struct sctp_association *)asoc;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +807,21 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/*
+	 * Once we have a sack generated, check to see what our sack
+	 * generation is, if its 0, reset the transports to 0, and reset
+	 * the association generation to 1
+	 *
+	 * The idea is that zero is never used as a valid generation for the
+	 * association so no transport will match after a wrap event like this,
+	 * Until the next sack
+	 */ 
+	if (++aptr->peer.sack_generation = 0) {
+		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+				    transports)
+			trans->sack_generation = 0;
+		aptr->peer.sack_generation = 1;
+	}
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index b026ba0..1dcceb6 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
 	memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+	peer->sack_generation = 0;
+
 	/* From 6.3.1 RTO Calculation:
 	 *
 	 * C1) Until an RTT measurement has been made for a packet sent to the
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..b5fb7c4 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->sack_generation +				trans->asoc->peer.sack_generation;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-29 20:15   ` Neil Horman
@ 2012-06-29 20:19     ` Vlad Yasevich
  -1 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-29 20:19 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/29/2012 04:15 PM, Neil Horman wrote:
> It was noticed recently that when we send data on a transport, its possible that
> we might bundle a sack that arrived on a different transport.  While this isn't
> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> 2960:
>
>   An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>     etc.) to the same destination transport address from which it
>     received the DATA or control chunk to which it is replying.  This
>     rule should also be followed if the endpoint is bundling DATA chunks
>     together with the reply chunk.
>
> This patch seeks to correct that.  It restricts the bundling of sack operations
> to only those transports which have moved the ctsn of the association forward
> since the last sack.  By doing this we guarantee that we only bundle outbound
> saks on a transport that has received a chunk since the last sack.  This brings
> us into stricter compliance with the RFC.
>
> Vlad had initially suggested that we strictly allow only sack bundling on the
> transport that last moved the ctsn forward.  While this makes sense, I was
> concerned that doing so prevented us from bundling in the case where we had
> received chunks that moved the ctsn on multiple transports.  In those cases, the
> RFC allows us to select any of the transports having received chunks to bundle
> the sack on.  so I've modified the approach to allow for that, by adding a state
> variable to each transport that tracks weather it has moved the ctsn since the
> last sack.  This I think keeps our behavior (and performance), close enough to
> our current profile that I think we can do this without a sysctl knob to
> enable/disable it.
>
> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> CC: Vlad Yaseivch<vyasevich@gmail.com>
> CC: David S. Miller<davem@davemloft.net>
> CC: linux-sctp@vger.kernel.org
> Reported-by: Michele Baldessari<michele@redhat.com>
> Reported-by: sorin serban<sserban@redhat.com>
>

Thanks Neil.  Looks good.

Acked-by: Vlad Yasevich <vyasevich@gmail.com>

-vlad

> ---
> Change Notes:
> V2)
> 	* Removed unused variable as per Dave M. Request
> 	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
> V3)
> 	* Switched test to use pkt->transport rather than chunk->transport
> 	* Modified detection of sacka-able transport.  Instead of just setting
> 	  and clearning a flag, we now mark each transport and association with
> 	  a sack generation tag.  We increment the associations generation on
> 	  every sack, and assign that generation tag to every transport that
> 	  updates the ctsn.  This prevents us from having to iterate over a for
> 	  loop on every sack, which is much more scalable.
> V4)
> 	* Fixed up wrapping comment and logic
> V5)
> 	* Simplified wrap logic further per request from vlad
> ---
>   include/net/sctp/structs.h |    4 ++++
>   include/net/sctp/tsnmap.h  |    3 ++-
>   net/sctp/associola.c       |    1 +
>   net/sctp/output.c          |    9 +++++++--
>   net/sctp/sm_make_chunk.c   |   17 +++++++++++++++++
>   net/sctp/sm_sideeffect.c   |    2 +-
>   net/sctp/transport.c       |    2 ++
>   net/sctp/tsnmap.c          |    6 +++++-
>   net/sctp/ulpevent.c        |    3 ++-
>   net/sctp/ulpqueue.c        |    2 +-
>   10 files changed, 42 insertions(+), 7 deletions(-)
>
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index e4652fe..fecdf31 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -912,6 +912,9 @@ struct sctp_transport {
>   		/* Is this structure kfree()able? */
>   		malloced:1;
>
> +	/* Has this transport moved the ctsn since we last sacked */
> +	__u32 sack_generation;
> +
>   	struct flowi fl;
>
>   	/* This is the peer's IP address and port. */
> @@ -1584,6 +1587,7 @@ struct sctp_association {
>   		 */
>   		__u8    sack_needed;     /* Do we need to sack the peer? */
>   		__u32	sack_cnt;
> +		__u32	sack_generation;
>
>   		/* These are capabilities which our peer advertised.  */
>   		__u8	ecn_capable:1,	    /* Can peer do ECN? */
> diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
> index e7728bc..2c5d2b4 100644
> --- a/include/net/sctp/tsnmap.h
> +++ b/include/net/sctp/tsnmap.h
> @@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
>   int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
> +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
> +		     struct sctp_transport *trans);
>
>   /* Mark this TSN and all lower as seen. */
>   void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 5bc9ab1..b16517e 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
>   	 */
>   	asoc->peer.sack_needed = 1;
>   	asoc->peer.sack_cnt = 0;
> +	asoc->peer.sack_generation = 1;
>
>   	/* Assume that the peer will tell us if he recognizes ASCONF
>   	 * as part of INIT exchange.
> diff --git a/net/sctp/output.c b/net/sctp/output.c
> index f1b7d4b..0de6cd5 100644
> --- a/net/sctp/output.c
> +++ b/net/sctp/output.c
> @@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>   	 */
>   	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
>   	!pkt->has_cookie_echo) {
> -		struct sctp_association *asoc;
>   		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +
>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>
>   		/* If the SACK timer is running, we have a pending SACK */
>   		if (timer_pending(timer)) {
>   			struct sctp_chunk *sack;
> +
> +			if (pkt->transport->sack_generation !=
> +			    pkt->transport->asoc->peer.sack_generation)
> +				return retval;
> +
>   			asoc->a_rwnd = asoc->rwnd;
>   			sack = sctp_make_sack(asoc);
>   			if (sack) {
> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> index a85eeeb..6486cac 100644
> --- a/net/sctp/sm_make_chunk.c
> +++ b/net/sctp/sm_make_chunk.c
> @@ -734,8 +734,10 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   	int len;
>   	__u32 ctsn;
>   	__u16 num_gabs, num_dup_tsns;
> +	struct sctp_association *aptr = (struct sctp_association *)asoc;
>   	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
>   	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
> +	struct sctp_transport *trans;
>
>   	memset(gabs, 0, sizeof(gabs));
>   	ctsn = sctp_tsnmap_get_ctsn(map);
> @@ -805,6 +807,21 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
>   				 sctp_tsnmap_get_dups(map));
>
> +	/*
> +	 * Once we have a sack generated, check to see what our sack
> +	 * generation is, if its 0, reset the transports to 0, and reset
> +	 * the association generation to 1
> +	 *
> +	 * The idea is that zero is never used as a valid generation for the
> +	 * association so no transport will match after a wrap event like this,
> +	 * Until the next sack
> +	 */
> +	if (++aptr->peer.sack_generation == 0) {
> +		list_for_each_entry(trans,&asoc->peer.transport_addr_list,
> +				    transports)
> +			trans->sack_generation = 0;
> +		aptr->peer.sack_generation = 1;
> +	}
>   nodata:
>   	return retval;
>   }
> diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
> index c96d1a8..8716da1 100644
> --- a/net/sctp/sm_sideeffect.c
> +++ b/net/sctp/sm_sideeffect.c
> @@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
>   		case SCTP_CMD_REPORT_TSN:
>   			/* Record the arrival of a TSN.  */
>   			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -						 cmd->obj.u32);
> +						 cmd->obj.u32, NULL);
>   			break;
>
>   		case SCTP_CMD_REPORT_FWDTSN:
> diff --git a/net/sctp/transport.c b/net/sctp/transport.c
> index b026ba0..1dcceb6 100644
> --- a/net/sctp/transport.c
> +++ b/net/sctp/transport.c
> @@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
>   	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
>   	memset(&peer->saddr, 0, sizeof(union sctp_addr));
>
> +	peer->sack_generation = 0;
> +
>   	/* From 6.3.1 RTO Calculation:
>   	 *
>   	 * C1) Until an RTT measurement has been made for a packet sent to the
> diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
> index f1e40ceb..b5fb7c4 100644
> --- a/net/sctp/tsnmap.c
> +++ b/net/sctp/tsnmap.c
> @@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
>
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
> +int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
> +		     struct sctp_transport *trans)
>   {
>   	u16 gap;
>
> @@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>   		 */
>   		map->max_tsn_seen++;
>   		map->cumulative_tsn_ack_point++;
> +		if (trans)
> +			trans->sack_generation =
> +				trans->asoc->peer.sack_generation;
>   		map->base_tsn++;
>   	} else {
>   		/* Either we already have a gap, or about to record a gap, so
> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
> index 8a84017..33d8947 100644
> --- a/net/sctp/ulpevent.c
> +++ b/net/sctp/ulpevent.c
> @@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
>   	 * can mark it as received so the tsn_map is updated correctly.
>   	 */
>   	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -			     ntohl(chunk->subh.data_hdr->tsn)))
> +			     ntohl(chunk->subh.data_hdr->tsn),
> +			     chunk->transport))
>   		goto fail_mark;
>
>   	/* First calculate the padding, so we don't inadvertently
> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
> index f2d1de7..f5a6a4f 100644
> --- a/net/sctp/ulpqueue.c
> +++ b/net/sctp/ulpqueue.c
> @@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
>   	if (chunk&&  (freed>= needed)) {
>   		__u32 tsn;
>   		tsn = ntohl(chunk->subh.data_hdr->tsn);
> -		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
> +		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
>   		sctp_ulpq_tail_data(ulpq, chunk, gfp);
>
>   		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-29 20:19     ` Vlad Yasevich
  0 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-06-29 20:19 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, David S. Miller, linux-sctp

On 06/29/2012 04:15 PM, Neil Horman wrote:
> It was noticed recently that when we send data on a transport, its possible that
> we might bundle a sack that arrived on a different transport.  While this isn't
> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> 2960:
>
>   An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>     etc.) to the same destination transport address from which it
>     received the DATA or control chunk to which it is replying.  This
>     rule should also be followed if the endpoint is bundling DATA chunks
>     together with the reply chunk.
>
> This patch seeks to correct that.  It restricts the bundling of sack operations
> to only those transports which have moved the ctsn of the association forward
> since the last sack.  By doing this we guarantee that we only bundle outbound
> saks on a transport that has received a chunk since the last sack.  This brings
> us into stricter compliance with the RFC.
>
> Vlad had initially suggested that we strictly allow only sack bundling on the
> transport that last moved the ctsn forward.  While this makes sense, I was
> concerned that doing so prevented us from bundling in the case where we had
> received chunks that moved the ctsn on multiple transports.  In those cases, the
> RFC allows us to select any of the transports having received chunks to bundle
> the sack on.  so I've modified the approach to allow for that, by adding a state
> variable to each transport that tracks weather it has moved the ctsn since the
> last sack.  This I think keeps our behavior (and performance), close enough to
> our current profile that I think we can do this without a sysctl knob to
> enable/disable it.
>
> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> CC: Vlad Yaseivch<vyasevich@gmail.com>
> CC: David S. Miller<davem@davemloft.net>
> CC: linux-sctp@vger.kernel.org
> Reported-by: Michele Baldessari<michele@redhat.com>
> Reported-by: sorin serban<sserban@redhat.com>
>

Thanks Neil.  Looks good.

Acked-by: Vlad Yasevich <vyasevich@gmail.com>

-vlad

> ---
> Change Notes:
> V2)
> 	* Removed unused variable as per Dave M. Request
> 	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
> V3)
> 	* Switched test to use pkt->transport rather than chunk->transport
> 	* Modified detection of sacka-able transport.  Instead of just setting
> 	  and clearning a flag, we now mark each transport and association with
> 	  a sack generation tag.  We increment the associations generation on
> 	  every sack, and assign that generation tag to every transport that
> 	  updates the ctsn.  This prevents us from having to iterate over a for
> 	  loop on every sack, which is much more scalable.
> V4)
> 	* Fixed up wrapping comment and logic
> V5)
> 	* Simplified wrap logic further per request from vlad
> ---
>   include/net/sctp/structs.h |    4 ++++
>   include/net/sctp/tsnmap.h  |    3 ++-
>   net/sctp/associola.c       |    1 +
>   net/sctp/output.c          |    9 +++++++--
>   net/sctp/sm_make_chunk.c   |   17 +++++++++++++++++
>   net/sctp/sm_sideeffect.c   |    2 +-
>   net/sctp/transport.c       |    2 ++
>   net/sctp/tsnmap.c          |    6 +++++-
>   net/sctp/ulpevent.c        |    3 ++-
>   net/sctp/ulpqueue.c        |    2 +-
>   10 files changed, 42 insertions(+), 7 deletions(-)
>
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index e4652fe..fecdf31 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -912,6 +912,9 @@ struct sctp_transport {
>   		/* Is this structure kfree()able? */
>   		malloced:1;
>
> +	/* Has this transport moved the ctsn since we last sacked */
> +	__u32 sack_generation;
> +
>   	struct flowi fl;
>
>   	/* This is the peer's IP address and port. */
> @@ -1584,6 +1587,7 @@ struct sctp_association {
>   		 */
>   		__u8    sack_needed;     /* Do we need to sack the peer? */
>   		__u32	sack_cnt;
> +		__u32	sack_generation;
>
>   		/* These are capabilities which our peer advertised.  */
>   		__u8	ecn_capable:1,	    /* Can peer do ECN? */
> diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
> index e7728bc..2c5d2b4 100644
> --- a/include/net/sctp/tsnmap.h
> +++ b/include/net/sctp/tsnmap.h
> @@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
>   int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
> +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
> +		     struct sctp_transport *trans);
>
>   /* Mark this TSN and all lower as seen. */
>   void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 5bc9ab1..b16517e 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
>   	 */
>   	asoc->peer.sack_needed = 1;
>   	asoc->peer.sack_cnt = 0;
> +	asoc->peer.sack_generation = 1;
>
>   	/* Assume that the peer will tell us if he recognizes ASCONF
>   	 * as part of INIT exchange.
> diff --git a/net/sctp/output.c b/net/sctp/output.c
> index f1b7d4b..0de6cd5 100644
> --- a/net/sctp/output.c
> +++ b/net/sctp/output.c
> @@ -240,14 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
>   	 */
>   	if (sctp_chunk_is_data(chunk)&&  !pkt->has_sack&&
>   	!pkt->has_cookie_echo) {
> -		struct sctp_association *asoc;
>   		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +
>   		timer =&asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
>
>   		/* If the SACK timer is running, we have a pending SACK */
>   		if (timer_pending(timer)) {
>   			struct sctp_chunk *sack;
> +
> +			if (pkt->transport->sack_generation !> +			    pkt->transport->asoc->peer.sack_generation)
> +				return retval;
> +
>   			asoc->a_rwnd = asoc->rwnd;
>   			sack = sctp_make_sack(asoc);
>   			if (sack) {
> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> index a85eeeb..6486cac 100644
> --- a/net/sctp/sm_make_chunk.c
> +++ b/net/sctp/sm_make_chunk.c
> @@ -734,8 +734,10 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   	int len;
>   	__u32 ctsn;
>   	__u16 num_gabs, num_dup_tsns;
> +	struct sctp_association *aptr = (struct sctp_association *)asoc;
>   	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
>   	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
> +	struct sctp_transport *trans;
>
>   	memset(gabs, 0, sizeof(gabs));
>   	ctsn = sctp_tsnmap_get_ctsn(map);
> @@ -805,6 +807,21 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
>   		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
>   				 sctp_tsnmap_get_dups(map));
>
> +	/*
> +	 * Once we have a sack generated, check to see what our sack
> +	 * generation is, if its 0, reset the transports to 0, and reset
> +	 * the association generation to 1
> +	 *
> +	 * The idea is that zero is never used as a valid generation for the
> +	 * association so no transport will match after a wrap event like this,
> +	 * Until the next sack
> +	 */
> +	if (++aptr->peer.sack_generation = 0) {
> +		list_for_each_entry(trans,&asoc->peer.transport_addr_list,
> +				    transports)
> +			trans->sack_generation = 0;
> +		aptr->peer.sack_generation = 1;
> +	}
>   nodata:
>   	return retval;
>   }
> diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
> index c96d1a8..8716da1 100644
> --- a/net/sctp/sm_sideeffect.c
> +++ b/net/sctp/sm_sideeffect.c
> @@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
>   		case SCTP_CMD_REPORT_TSN:
>   			/* Record the arrival of a TSN.  */
>   			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -						 cmd->obj.u32);
> +						 cmd->obj.u32, NULL);
>   			break;
>
>   		case SCTP_CMD_REPORT_FWDTSN:
> diff --git a/net/sctp/transport.c b/net/sctp/transport.c
> index b026ba0..1dcceb6 100644
> --- a/net/sctp/transport.c
> +++ b/net/sctp/transport.c
> @@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
>   	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
>   	memset(&peer->saddr, 0, sizeof(union sctp_addr));
>
> +	peer->sack_generation = 0;
> +
>   	/* From 6.3.1 RTO Calculation:
>   	 *
>   	 * C1) Until an RTT measurement has been made for a packet sent to the
> diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
> index f1e40ceb..b5fb7c4 100644
> --- a/net/sctp/tsnmap.c
> +++ b/net/sctp/tsnmap.c
> @@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
>
>
>   /* Mark this TSN as seen.  */
> -int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
> +int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
> +		     struct sctp_transport *trans)
>   {
>   	u16 gap;
>
> @@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
>   		 */
>   		map->max_tsn_seen++;
>   		map->cumulative_tsn_ack_point++;
> +		if (trans)
> +			trans->sack_generation > +				trans->asoc->peer.sack_generation;
>   		map->base_tsn++;
>   	} else {
>   		/* Either we already have a gap, or about to record a gap, so
> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
> index 8a84017..33d8947 100644
> --- a/net/sctp/ulpevent.c
> +++ b/net/sctp/ulpevent.c
> @@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
>   	 * can mark it as received so the tsn_map is updated correctly.
>   	 */
>   	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
> -			     ntohl(chunk->subh.data_hdr->tsn)))
> +			     ntohl(chunk->subh.data_hdr->tsn),
> +			     chunk->transport))
>   		goto fail_mark;
>
>   	/* First calculate the padding, so we don't inadvertently
> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
> index f2d1de7..f5a6a4f 100644
> --- a/net/sctp/ulpqueue.c
> +++ b/net/sctp/ulpqueue.c
> @@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
>   	if (chunk&&  (freed>= needed)) {
>   		__u32 tsn;
>   		tsn = ntohl(chunk->subh.data_hdr->tsn);
> -		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
> +		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
>   		sctp_ulpq_tail_data(ulpq, chunk, gfp);
>
>   		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-29 20:15   ` Neil Horman
@ 2012-06-29 23:34     ` David Miller
  -1 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-06-29 23:34 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Fri, 29 Jun 2012 16:15:29 -0400

> +	/* Has this transport moved the ctsn since we last sacked */
> +	__u32 sack_generation;
> +
 ...
> +		__u32	sack_generation;

These are __u32 but they only take on the value '1' or '0'.  Please
use bool and give it a more reasonable name, a name that describes
how it is really a predicate.

> -		struct sctp_association *asoc;
>  		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +

Please leave asoc where it was, on the first line.  We encourage
listing local variables such that the longest lines come first,
then gradually shorter and short lines.

> +	/*
> +	 * Once we have a sack generated, check to see what our sack
> +	 * generation is, if its 0, reset the transports to 0, and reset

Please format:

  /* Like
   * this.
   */

Thanks.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-29 23:34     ` David Miller
  0 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-06-29 23:34 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Fri, 29 Jun 2012 16:15:29 -0400

> +	/* Has this transport moved the ctsn since we last sacked */
> +	__u32 sack_generation;
> +
 ...
> +		__u32	sack_generation;

These are __u32 but they only take on the value '1' or '0'.  Please
use bool and give it a more reasonable name, a name that describes
how it is really a predicate.

> -		struct sctp_association *asoc;
>  		struct timer_list *timer;
> -		asoc = pkt->transport->asoc;
> +		struct sctp_association *asoc = pkt->transport->asoc;
> +

Please leave asoc where it was, on the first line.  We encourage
listing local variables such that the longest lines come first,
then gradually shorter and short lines.

> +	/*
> +	 * Once we have a sack generated, check to see what our sack
> +	 * generation is, if its 0, reset the transports to 0, and reset

Please format:

  /* Like
   * this.
   */

Thanks.


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-29 23:34     ` David Miller
@ 2012-06-30 12:26       ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-30 12:26 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Fri, Jun 29, 2012 at 04:34:08PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Fri, 29 Jun 2012 16:15:29 -0400
> 
> > +	/* Has this transport moved the ctsn since we last sacked */
> > +	__u32 sack_generation;
> > +
>  ...
> > +		__u32	sack_generation;
> 
> These are __u32 but they only take on the value '1' or '0'.  Please
> use bool and give it a more reasonable name, a name that describes
> how it is really a predicate.
> 
This is wrong.  Its a counter that increments every time we call sctp_make_sack,
so that we can create a unique generation identifier for use in tagging which
transports move ctsn in a given generation.  It saves us from having to iterate
over a list every time we send a sack. 

> > -		struct sctp_association *asoc;
> >  		struct timer_list *timer;
> > -		asoc = pkt->transport->asoc;
> > +		struct sctp_association *asoc = pkt->transport->asoc;
> > +
> 
> Please leave asoc where it was, on the first line.  We encourage
> listing local variables such that the longest lines come first,
> then gradually shorter and short lines.
> 
> > +	/*
> > +	 * Once we have a sack generated, check to see what our sack
> > +	 * generation is, if its 0, reset the transports to 0, and reset
> 
> Please format:
> 
>   /* Like
>    * this.
>    */
> 
> Thanks.
> 
Very well, I'll repost in the next few days
Neil

> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-30 12:26       ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-30 12:26 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Fri, Jun 29, 2012 at 04:34:08PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Fri, 29 Jun 2012 16:15:29 -0400
> 
> > +	/* Has this transport moved the ctsn since we last sacked */
> > +	__u32 sack_generation;
> > +
>  ...
> > +		__u32	sack_generation;
> 
> These are __u32 but they only take on the value '1' or '0'.  Please
> use bool and give it a more reasonable name, a name that describes
> how it is really a predicate.
> 
This is wrong.  Its a counter that increments every time we call sctp_make_sack,
so that we can create a unique generation identifier for use in tagging which
transports move ctsn in a given generation.  It saves us from having to iterate
over a list every time we send a sack. 

> > -		struct sctp_association *asoc;
> >  		struct timer_list *timer;
> > -		asoc = pkt->transport->asoc;
> > +		struct sctp_association *asoc = pkt->transport->asoc;
> > +
> 
> Please leave asoc where it was, on the first line.  We encourage
> listing local variables such that the longest lines come first,
> then gradually shorter and short lines.
> 
> > +	/*
> > +	 * Once we have a sack generated, check to see what our sack
> > +	 * generation is, if its 0, reset the transports to 0, and reset
> 
> Please format:
> 
>   /* Like
>    * this.
>    */
> 
> Thanks.
> 
Very well, I'll repost in the next few days
Neil

> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-26 20:31 ` Neil Horman
@ 2012-06-30 13:04   ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-30 13:04 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
V3)
	* Switched test to use pkt->transport rather than chunk->transport
	* Modified detection of sacka-able transport.  Instead of just setting
	  and clearning a flag, we now mark each transport and association with
	  a sack generation tag.  We increment the associations generation on
	  every sack, and assign that generation tag to every transport that
	  updates the ctsn.  This prevents us from having to iterate over a for
	  loop on every sack, which is much more scalable.
V4)
	* Fixed up wrapping comment and logic
V5)
	* Simplified wrap logic further per request from vlad
V6)
	* Changed some style point as per request from Dave M.
---
 include/net/sctp/structs.h |    4 ++++
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/associola.c       |    1 +
 net/sctp/output.c          |    5 +++++
 net/sctp/sm_make_chunk.c   |   16 ++++++++++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/transport.c       |    2 ++
 net/sctp/tsnmap.c          |    6 +++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 10 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..fecdf31 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -912,6 +912,9 @@ struct sctp_transport {
 		/* Is this structure kfree()able? */
 		malloced:1;
 
+	/* Has this transport moved the ctsn since we last sacked */
+	__u32 sack_generation;
+
 	struct flowi fl;
 
 	/* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
 		 */
 		__u8    sack_needed;     /* Do we need to sack the peer? */
 		__u32	sack_cnt;
+		__u32	sack_generation;
 
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable:1,	    /* Can peer do ECN? */
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5bc9ab1..b16517e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	 */
 	asoc->peer.sack_needed = 1;
 	asoc->peer.sack_cnt = 0;
+	asoc->peer.sack_generation = 1;
 
 	/* Assume that the peer will tell us if he recognizes ASCONF
 	 * as part of INIT exchange.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..6ae47ac 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -248,6 +248,11 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
+
+			if (pkt->transport->sack_generation !=
+			    pkt->transport->asoc->peer.sack_generation)
+				return retval;
+
 			asoc->a_rwnd = asoc->rwnd;
 			sack = sctp_make_sack(asoc);
 			if (sack) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..098cff5 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -734,8 +734,10 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	int len;
 	__u32 ctsn;
 	__u16 num_gabs, num_dup_tsns;
+	struct sctp_association *aptr = (struct sctp_association *)asoc;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +807,20 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/* Once we have a sack generated, check to see what our sack
+	 * generation is, if its 0, reset the transports to 0, and reset
+	 * the association generation to 1
+	 *
+	 * The idea is that zero is never used as a valid generation for the
+	 * association so no transport will match after a wrap event like this,
+	 * Until the next sack
+	 */ 
+	if (++aptr->peer.sack_generation == 0) {
+		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+				    transports)
+			trans->sack_generation = 0;
+		aptr->peer.sack_generation = 1;
+	}
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index b026ba0..1dcceb6 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
 	memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+	peer->sack_generation = 0;
+
 	/* From 6.3.1 RTO Calculation:
 	 *
 	 * C1) Until an RTT measurement has been made for a packet sent to the
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..b5fb7c4 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->sack_generation =
+				trans->asoc->peer.sack_generation;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-06-30 13:04   ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-06-30 13:04 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Vlad Yaseivch, David S. Miller, linux-sctp

It was noticed recently that when we send data on a transport, its possible that
we might bundle a sack that arrived on a different transport.  While this isn't
a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
2960:

 An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
   etc.) to the same destination transport address from which it
   received the DATA or control chunk to which it is replying.  This
   rule should also be followed if the endpoint is bundling DATA chunks
   together with the reply chunk.

This patch seeks to correct that.  It restricts the bundling of sack operations
to only those transports which have moved the ctsn of the association forward
since the last sack.  By doing this we guarantee that we only bundle outbound
saks on a transport that has received a chunk since the last sack.  This brings
us into stricter compliance with the RFC.

Vlad had initially suggested that we strictly allow only sack bundling on the
transport that last moved the ctsn forward.  While this makes sense, I was
concerned that doing so prevented us from bundling in the case where we had
received chunks that moved the ctsn on multiple transports.  In those cases, the
RFC allows us to select any of the transports having received chunks to bundle
the sack on.  so I've modified the approach to allow for that, by adding a state
variable to each transport that tracks weather it has moved the ctsn since the
last sack.  This I think keeps our behavior (and performance), close enough to
our current profile that I think we can do this without a sysctl knob to
enable/disable it.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Vlad Yaseivch <vyasevich@gmail.com>
CC: David S. Miller <davem@davemloft.net>
CC: linux-sctp@vger.kernel.org
Reported-by: Michele Baldessari <michele@redhat.com>
Reported-by: sorin serban <sserban@redhat.com>

---
Change Notes:
V2)
	* Removed unused variable as per Dave M. Request
	* Delayed rwnd adjustment until we are sure we will sack (Vlad Y.)
V3)
	* Switched test to use pkt->transport rather than chunk->transport
	* Modified detection of sacka-able transport.  Instead of just setting
	  and clearning a flag, we now mark each transport and association with
	  a sack generation tag.  We increment the associations generation on
	  every sack, and assign that generation tag to every transport that
	  updates the ctsn.  This prevents us from having to iterate over a for
	  loop on every sack, which is much more scalable.
V4)
	* Fixed up wrapping comment and logic
V5)
	* Simplified wrap logic further per request from vlad
V6)
	* Changed some style point as per request from Dave M.
---
 include/net/sctp/structs.h |    4 ++++
 include/net/sctp/tsnmap.h  |    3 ++-
 net/sctp/associola.c       |    1 +
 net/sctp/output.c          |    5 +++++
 net/sctp/sm_make_chunk.c   |   16 ++++++++++++++++
 net/sctp/sm_sideeffect.c   |    2 +-
 net/sctp/transport.c       |    2 ++
 net/sctp/tsnmap.c          |    6 +++++-
 net/sctp/ulpevent.c        |    3 ++-
 net/sctp/ulpqueue.c        |    2 +-
 10 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index e4652fe..fecdf31 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -912,6 +912,9 @@ struct sctp_transport {
 		/* Is this structure kfree()able? */
 		malloced:1;
 
+	/* Has this transport moved the ctsn since we last sacked */
+	__u32 sack_generation;
+
 	struct flowi fl;
 
 	/* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
 		 */
 		__u8    sack_needed;     /* Do we need to sack the peer? */
 		__u32	sack_cnt;
+		__u32	sack_generation;
 
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable:1,	    /* Can peer do ECN? */
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index e7728bc..2c5d2b4 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+		     struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5bc9ab1..b16517e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	 */
 	asoc->peer.sack_needed = 1;
 	asoc->peer.sack_cnt = 0;
+	asoc->peer.sack_generation = 1;
 
 	/* Assume that the peer will tell us if he recognizes ASCONF
 	 * as part of INIT exchange.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f1b7d4b..6ae47ac 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -248,6 +248,11 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 		/* If the SACK timer is running, we have a pending SACK */
 		if (timer_pending(timer)) {
 			struct sctp_chunk *sack;
+
+			if (pkt->transport->sack_generation !+			    pkt->transport->asoc->peer.sack_generation)
+				return retval;
+
 			asoc->a_rwnd = asoc->rwnd;
 			sack = sctp_make_sack(asoc);
 			if (sack) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index a85eeeb..098cff5 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -734,8 +734,10 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 	int len;
 	__u32 ctsn;
 	__u16 num_gabs, num_dup_tsns;
+	struct sctp_association *aptr = (struct sctp_association *)asoc;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+	struct sctp_transport *trans;
 
 	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +807,20 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
 				 sctp_tsnmap_get_dups(map));
 
+	/* Once we have a sack generated, check to see what our sack
+	 * generation is, if its 0, reset the transports to 0, and reset
+	 * the association generation to 1
+	 *
+	 * The idea is that zero is never used as a valid generation for the
+	 * association so no transport will match after a wrap event like this,
+	 * Until the next sack
+	 */ 
+	if (++aptr->peer.sack_generation = 0) {
+		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+				    transports)
+			trans->sack_generation = 0;
+		aptr->peer.sack_generation = 1;
+	}
 nodata:
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index c96d1a8..8716da1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-						 cmd->obj.u32);
+						 cmd->obj.u32, NULL);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index b026ba0..1dcceb6 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 	peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
 	memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+	peer->sack_generation = 0;
+
 	/* From 6.3.1 RTO Calculation:
 	 *
 	 * C1) Until an RTT measurement has been made for a packet sent to the
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f1e40ceb..b5fb7c4 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+		     struct sctp_transport *trans)
 {
 	u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 		 */
 		map->max_tsn_seen++;
 		map->cumulative_tsn_ack_point++;
+		if (trans)
+			trans->sack_generation +				trans->asoc->peer.sack_generation;
 		map->base_tsn++;
 	} else {
 		/* Either we already have a gap, or about to record a gap, so
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 8a84017..33d8947 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
 	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-			     ntohl(chunk->subh.data_hdr->tsn)))
+			     ntohl(chunk->subh.data_hdr->tsn),
+			     chunk->transport))
 		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index f2d1de7..f5a6a4f 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	if (chunk && (freed >= needed)) {
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
-		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
 		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
 		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-30 12:26       ` Neil Horman
@ 2012-07-01  0:38         ` David Miller
  -1 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01  0:38 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Sat, 30 Jun 2012 08:26:47 -0400

> This is wrong.  Its a counter that increments every time we call sctp_make_sack,
> so that we can create a unique generation identifier for use in tagging which
> transports move ctsn in a given generation.  It saves us from having to iterate
> over a list every time we send a sack. 

Sorry, I missed the counter bump.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v5] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-01  0:38         ` David Miller
  0 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01  0:38 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Sat, 30 Jun 2012 08:26:47 -0400

> This is wrong.  Its a counter that increments every time we call sctp_make_sack,
> so that we can create a unique generation identifier for use in tagging which
> transports move ctsn in a given generation.  It saves us from having to iterate
> over a list every time we send a sack. 

Sorry, I missed the counter bump.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-06-30 13:04   ` Neil Horman
@ 2012-07-01  0:39     ` David Miller
  -1 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01  0:39 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Sat, 30 Jun 2012 09:04:26 -0400

> It was noticed recently that when we send data on a transport, its possible that
> we might bundle a sack that arrived on a different transport.  While this isn't
> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> 2960:
> 
>  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>    etc.) to the same destination transport address from which it
>    received the DATA or control chunk to which it is replying.  This
>    rule should also be followed if the endpoint is bundling DATA chunks
>    together with the reply chunk.
> 
> This patch seeks to correct that.  It restricts the bundling of sack operations
> to only those transports which have moved the ctsn of the association forward
> since the last sack.  By doing this we guarantee that we only bundle outbound
> saks on a transport that has received a chunk since the last sack.  This brings
> us into stricter compliance with the RFC.
> 
> Vlad had initially suggested that we strictly allow only sack bundling on the
> transport that last moved the ctsn forward.  While this makes sense, I was
> concerned that doing so prevented us from bundling in the case where we had
> received chunks that moved the ctsn on multiple transports.  In those cases, the
> RFC allows us to select any of the transports having received chunks to bundle
> the sack on.  so I've modified the approach to allow for that, by adding a state
> variable to each transport that tracks weather it has moved the ctsn since the
> last sack.  This I think keeps our behavior (and performance), close enough to
> our current profile that I think we can do this without a sysctl knob to
> enable/disable it.
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Vlad Yaseivch <vyasevich@gmail.com>
> CC: David S. Miller <davem@davemloft.net>
> CC: linux-sctp@vger.kernel.org
> Reported-by: Michele Baldessari <michele@redhat.com>
> Reported-by: sorin serban <sserban@redhat.com>

Once this has Vlad's ACK I'll apply it.

There has to be a better way to handle this situation, wherein the
responsible party has ACK'd the patch but I just ask for a few coding
style fixups and whatnot.  As it stands now I have to twiddle my
thumbs waiting for the new ACK.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-01  0:39     ` David Miller
  0 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01  0:39 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Sat, 30 Jun 2012 09:04:26 -0400

> It was noticed recently that when we send data on a transport, its possible that
> we might bundle a sack that arrived on a different transport.  While this isn't
> a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> 2960:
> 
>  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>    etc.) to the same destination transport address from which it
>    received the DATA or control chunk to which it is replying.  This
>    rule should also be followed if the endpoint is bundling DATA chunks
>    together with the reply chunk.
> 
> This patch seeks to correct that.  It restricts the bundling of sack operations
> to only those transports which have moved the ctsn of the association forward
> since the last sack.  By doing this we guarantee that we only bundle outbound
> saks on a transport that has received a chunk since the last sack.  This brings
> us into stricter compliance with the RFC.
> 
> Vlad had initially suggested that we strictly allow only sack bundling on the
> transport that last moved the ctsn forward.  While this makes sense, I was
> concerned that doing so prevented us from bundling in the case where we had
> received chunks that moved the ctsn on multiple transports.  In those cases, the
> RFC allows us to select any of the transports having received chunks to bundle
> the sack on.  so I've modified the approach to allow for that, by adding a state
> variable to each transport that tracks weather it has moved the ctsn since the
> last sack.  This I think keeps our behavior (and performance), close enough to
> our current profile that I think we can do this without a sysctl knob to
> enable/disable it.
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Vlad Yaseivch <vyasevich@gmail.com>
> CC: David S. Miller <davem@davemloft.net>
> CC: linux-sctp@vger.kernel.org
> Reported-by: Michele Baldessari <michele@redhat.com>
> Reported-by: sorin serban <sserban@redhat.com>

Once this has Vlad's ACK I'll apply it.

There has to be a better way to handle this situation, wherein the
responsible party has ACK'd the patch but I just ask for a few coding
style fixups and whatnot.  As it stands now I have to twiddle my
thumbs waiting for the new ACK.


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-01  0:39     ` David Miller
@ 2012-07-01  3:17       ` Vlad Yasevich
  -1 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-07-01  3:17 UTC (permalink / raw)
  To: David Miller, nhorman; +Cc: netdev, linux-sctp

David Miller <davem@davemloft.net> wrote:

>From: Neil Horman <nhorman@tuxdriver.com>
>Date: Sat, 30 Jun 2012 09:04:26 -0400
>
>> It was noticed recently that when we send data on a transport, its
>possible that
>> we might bundle a sack that arrived on a different transport.  While
>this isn't
>> a major problem, it does go against the SHOULDAcm requirement in section
>6.4 of RFC
>> 2960:
>> 
>>  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>>    etc.) to the same destination transport address from which it
>>    received the DATA or control chunk to which it is replying.  This
>>    rule should also be followed if the endpoint is bundling DATA
>chunks
>>    together with the reply chunk.
>> 
>> This patch seeks to correct that.  It restricts the bundling of sack
>operations
>> to only those transports which have moved the ctsn of the association
>forward
>> since the last sack.  By doing this we guarantee that we only bundle
>outbound
>> saks on a transport that has received a chunk since the last sack. 
>This brings
>> us into stricter compliance with the RFC.
>> 
>> Vlad had initially suggested that we strictly allow only sack
>bundling on the
>> transport that last moved the ctsn forward.  While this makes sense,
>I was
>> concerned that doing so prevented us from bundling in the case where
>we had
>> received chunks that moved the ctsn on multiple transports.  In those
>cases, the
>> RFC allows us to select any of the transports having received chunks
>to bundle
>> the sack on.  so I've modified the approach to allow for that, by
>adding a state
>> variable to each transport that tracks weather it has moved the ctsn
>since the
>> last sack.  This I think keeps our behavior (and performance), close
>enough to
>> our current profile that I think we can do this without a sysctl knob
>to
>> enable/disable it.
>> 
>> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
>> CC: Vlad Yaseivch <vyasevich@gmail.com>
>> CC: David S. Miller <davem@davemloft.net>
>> CC: linux-sctp@vger.kernel.org
>> Reported-by: Michele Baldessari <michele@redhat.com>
>> Reported-by: sorin serban <sserban@redhat.com>
>
>Once this has Vlad's ACK I'll apply it.
>

Acked-by: Vlad Yasevich <vyasevich@gmail.com>

Sorry for the delay.

-vlad

>There has to be a better way to handle this situation, wherein the
>responsible party has ACK'd the patch but I just ask for a few coding
>style fixups and whatnot.  As it stands now I have to twiddle my
>thumbs waiting for the new ACK.


-- 
Sent from my Android phone with SkitMail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-01  3:17       ` Vlad Yasevich
  0 siblings, 0 replies; 66+ messages in thread
From: Vlad Yasevich @ 2012-07-01  3:17 UTC (permalink / raw)
  To: David Miller, nhorman; +Cc: netdev, linux-sctp

David Miller <davem@davemloft.net> wrote:

>From: Neil Horman <nhorman@tuxdriver.com>
>Date: Sat, 30 Jun 2012 09:04:26 -0400
>
>> It was noticed recently that when we send data on a transport, its
>possible that
>> we might bundle a sack that arrived on a different transport.  While
>this isn't
>> a major problem, it does go against the SHOULDAcm requirement in section
>6.4 of RFC
>> 2960:
>> 
>>  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
>>    etc.) to the same destination transport address from which it
>>    received the DATA or control chunk to which it is replying.  This
>>    rule should also be followed if the endpoint is bundling DATA
>chunks
>>    together with the reply chunk.
>> 
>> This patch seeks to correct that.  It restricts the bundling of sack
>operations
>> to only those transports which have moved the ctsn of the association
>forward
>> since the last sack.  By doing this we guarantee that we only bundle
>outbound
>> saks on a transport that has received a chunk since the last sack. 
>This brings
>> us into stricter compliance with the RFC.
>> 
>> Vlad had initially suggested that we strictly allow only sack
>bundling on the
>> transport that last moved the ctsn forward.  While this makes sense,
>I was
>> concerned that doing so prevented us from bundling in the case where
>we had
>> received chunks that moved the ctsn on multiple transports.  In those
>cases, the
>> RFC allows us to select any of the transports having received chunks
>to bundle
>> the sack on.  so I've modified the approach to allow for that, by
>adding a state
>> variable to each transport that tracks weather it has moved the ctsn
>since the
>> last sack.  This I think keeps our behavior (and performance), close
>enough to
>> our current profile that I think we can do this without a sysctl knob
>to
>> enable/disable it.
>> 
>> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
>> CC: Vlad Yaseivch <vyasevich@gmail.com>
>> CC: David S. Miller <davem@davemloft.net>
>> CC: linux-sctp@vger.kernel.org
>> Reported-by: Michele Baldessari <michele@redhat.com>
>> Reported-by: sorin serban <sserban@redhat.com>
>
>Once this has Vlad's ACK I'll apply it.
>

Acked-by: Vlad Yasevich <vyasevich@gmail.com>

Sorry for the delay.

-vlad

>There has to be a better way to handle this situation, wherein the
>responsible party has ACK'd the patch but I just ask for a few coding
>style fixups and whatnot.  As it stands now I have to twiddle my
>thumbs waiting for the new ACK.


-- 
Sent from my Android phone with SkitMail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-01  3:17       ` Vlad Yasevich
@ 2012-07-01  5:44         ` David Miller
  -1 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01  5:44 UTC (permalink / raw)
  To: vyasevich; +Cc: nhorman, netdev, linux-sctp

From: Vlad Yasevich <vyasevich@gmail.com>
Date: Sat, 30 Jun 2012 23:17:52 -0400

> David Miller <davem@davemloft.net> wrote:
> 
>>Once this has Vlad's ACK I'll apply it.
> 
> Acked-by: Vlad Yasevich <vyasevich@gmail.com>

Applied, thanks everyone.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-01  5:44         ` David Miller
  0 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01  5:44 UTC (permalink / raw)
  To: vyasevich; +Cc: nhorman, netdev, linux-sctp

From: Vlad Yasevich <vyasevich@gmail.com>
Date: Sat, 30 Jun 2012 23:17:52 -0400

> David Miller <davem@davemloft.net> wrote:
> 
>>Once this has Vlad's ACK I'll apply it.
> 
> Acked-by: Vlad Yasevich <vyasevich@gmail.com>

Applied, thanks everyone.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-01  0:39     ` David Miller
@ 2012-07-01 12:47       ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-01 12:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Sat, Jun 30, 2012 at 05:39:45PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Sat, 30 Jun 2012 09:04:26 -0400
> 
> > It was noticed recently that when we send data on a transport, its possible that
> > we might bundle a sack that arrived on a different transport.  While this isn't
> > a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> > 2960:
> > 
> >  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
> >    etc.) to the same destination transport address from which it
> >    received the DATA or control chunk to which it is replying.  This
> >    rule should also be followed if the endpoint is bundling DATA chunks
> >    together with the reply chunk.
> > 
> > This patch seeks to correct that.  It restricts the bundling of sack operations
> > to only those transports which have moved the ctsn of the association forward
> > since the last sack.  By doing this we guarantee that we only bundle outbound
> > saks on a transport that has received a chunk since the last sack.  This brings
> > us into stricter compliance with the RFC.
> > 
> > Vlad had initially suggested that we strictly allow only sack bundling on the
> > transport that last moved the ctsn forward.  While this makes sense, I was
> > concerned that doing so prevented us from bundling in the case where we had
> > received chunks that moved the ctsn on multiple transports.  In those cases, the
> > RFC allows us to select any of the transports having received chunks to bundle
> > the sack on.  so I've modified the approach to allow for that, by adding a state
> > variable to each transport that tracks weather it has moved the ctsn since the
> > last sack.  This I think keeps our behavior (and performance), close enough to
> > our current profile that I think we can do this without a sysctl knob to
> > enable/disable it.
> > 
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > CC: Vlad Yaseivch <vyasevich@gmail.com>
> > CC: David S. Miller <davem@davemloft.net>
> > CC: linux-sctp@vger.kernel.org
> > Reported-by: Michele Baldessari <michele@redhat.com>
> > Reported-by: sorin serban <sserban@redhat.com>
> 
> Once this has Vlad's ACK I'll apply it.
> 
Thanks!
> There has to be a better way to handle this situation, wherein the
> responsible party has ACK'd the patch but I just ask for a few coding
> style fixups and whatnot.  As it stands now I have to twiddle my
> thumbs waiting for the new ACK.
> 
Perhaps we could modify the SubmittingPatches document to indicate that an
Acked-by from a subsystem maintainer implicitly confers authority on the
upstream receiver to request reasonable stylistic changes that don't affect the
functionality of the patch in the interests of maintaining coding conventions.

i.e. Since vlad applied an acked-by to v5 of this patch, that would give you the
right to carry that ack forward to v6 because you only asked for style changes.

Thoughts?
Neil

> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-01 12:47       ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-01 12:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Sat, Jun 30, 2012 at 05:39:45PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Sat, 30 Jun 2012 09:04:26 -0400
> 
> > It was noticed recently that when we send data on a transport, its possible that
> > we might bundle a sack that arrived on a different transport.  While this isn't
> > a major problem, it does go against the SHOULD requirement in section 6.4 of RFC
> > 2960:
> > 
> >  An endpoint SHOULD transmit reply chunks (e.g., SACK, HEARTBEAT ACK,
> >    etc.) to the same destination transport address from which it
> >    received the DATA or control chunk to which it is replying.  This
> >    rule should also be followed if the endpoint is bundling DATA chunks
> >    together with the reply chunk.
> > 
> > This patch seeks to correct that.  It restricts the bundling of sack operations
> > to only those transports which have moved the ctsn of the association forward
> > since the last sack.  By doing this we guarantee that we only bundle outbound
> > saks on a transport that has received a chunk since the last sack.  This brings
> > us into stricter compliance with the RFC.
> > 
> > Vlad had initially suggested that we strictly allow only sack bundling on the
> > transport that last moved the ctsn forward.  While this makes sense, I was
> > concerned that doing so prevented us from bundling in the case where we had
> > received chunks that moved the ctsn on multiple transports.  In those cases, the
> > RFC allows us to select any of the transports having received chunks to bundle
> > the sack on.  so I've modified the approach to allow for that, by adding a state
> > variable to each transport that tracks weather it has moved the ctsn since the
> > last sack.  This I think keeps our behavior (and performance), close enough to
> > our current profile that I think we can do this without a sysctl knob to
> > enable/disable it.
> > 
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > CC: Vlad Yaseivch <vyasevich@gmail.com>
> > CC: David S. Miller <davem@davemloft.net>
> > CC: linux-sctp@vger.kernel.org
> > Reported-by: Michele Baldessari <michele@redhat.com>
> > Reported-by: sorin serban <sserban@redhat.com>
> 
> Once this has Vlad's ACK I'll apply it.
> 
Thanks!
> There has to be a better way to handle this situation, wherein the
> responsible party has ACK'd the patch but I just ask for a few coding
> style fixups and whatnot.  As it stands now I have to twiddle my
> thumbs waiting for the new ACK.
> 
Perhaps we could modify the SubmittingPatches document to indicate that an
Acked-by from a subsystem maintainer implicitly confers authority on the
upstream receiver to request reasonable stylistic changes that don't affect the
functionality of the patch in the interests of maintaining coding conventions.

i.e. Since vlad applied an acked-by to v5 of this patch, that would give you the
right to carry that ack forward to v6 because you only asked for style changes.

Thoughts?
Neil

> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-01 12:47       ` Neil Horman
@ 2012-07-01 21:43         ` David Miller
  -1 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01 21:43 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Sun, 1 Jul 2012 08:47:50 -0400

> Perhaps we could modify the SubmittingPatches document to indicate that an
> Acked-by from a subsystem maintainer implicitly confers authority on the
> upstream receiver to request reasonable stylistic changes that don't affect the
> functionality of the patch in the interests of maintaining coding conventions.

Yes, that would make sense.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-01 21:43         ` David Miller
  0 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-01 21:43 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Sun, 1 Jul 2012 08:47:50 -0400

> Perhaps we could modify the SubmittingPatches document to indicate that an
> Acked-by from a subsystem maintainer implicitly confers authority on the
> upstream receiver to request reasonable stylistic changes that don't affect the
> functionality of the patch in the interests of maintaining coding conventions.

Yes, that would make sense.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-01 21:43         ` David Miller
@ 2012-07-01 23:44           ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-01 23:44 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Sun, Jul 01, 2012 at 02:43:19PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Sun, 1 Jul 2012 08:47:50 -0400
> 
> > Perhaps we could modify the SubmittingPatches document to indicate that an
> > Acked-by from a subsystem maintainer implicitly confers authority on the
> > upstream receiver to request reasonable stylistic changes that don't affect the
> > functionality of the patch in the interests of maintaining coding conventions.
> 
> Yes, that would make sense.
> 


I'll propose it in a few days.
Neil

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-01 23:44           ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-01 23:44 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Sun, Jul 01, 2012 at 02:43:19PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Sun, 1 Jul 2012 08:47:50 -0400
> 
> > Perhaps we could modify the SubmittingPatches document to indicate that an
> > Acked-by from a subsystem maintainer implicitly confers authority on the
> > upstream receiver to request reasonable stylistic changes that don't affect the
> > functionality of the patch in the interests of maintaining coding conventions.
> 
> Yes, that would make sense.
> 


I'll propose it in a few days.
Neil


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-01 23:44           ` Neil Horman
@ 2012-07-02 12:25             ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-02 12:25 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Sun, Jul 01, 2012 at 07:44:25PM -0400, Neil Horman wrote:
> On Sun, Jul 01, 2012 at 02:43:19PM -0700, David Miller wrote:
> > From: Neil Horman <nhorman@tuxdriver.com>
> > Date: Sun, 1 Jul 2012 08:47:50 -0400
> > 
> > > Perhaps we could modify the SubmittingPatches document to indicate that an
> > > Acked-by from a subsystem maintainer implicitly confers authority on the
> > > upstream receiver to request reasonable stylistic changes that don't affect the
> > > functionality of the patch in the interests of maintaining coding conventions.
> > 
> > Yes, that would make sense.
> > 
> 
> 
> I'll propose it in a few days.
> Neil
> 
How does this language sound to you?


diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index c379a2a..1eaaeb1 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -414,6 +414,16 @@ the part which affects that maintainer's code.  Judgement should be used here.
 When in doubt people should refer to the original discussion in the mailing
 list archives.
 
+Note that an Acked-by: From a subsystem maintainer on a given patch confers
+upon the tree maintainer integrating the path the authority to carry those Acks
+forward through subsequent versions of a patch, as long as those versions do not
+significantly impact the functionality of the patch.  For example, say the isdn
+subsystem maintainer sends an Acked-by: on version 1 of a patch bound for the
+networking tree.  The networking maintainer then requests that some comments in
+the code be modified to comply with the CodingStyle document.  The networking
+tree maintanier may reapply the subsystem maintainers Acked-by: to the new
+version as no significant changes were made to the patch functionality.
+
 If a person has had the opportunity to comment on a patch, but has not
 provided such comments, you may optionally add a "Cc:" tag to the patch.
 This is the only tag which might be added without an explicit action by the

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-02 12:25             ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-02 12:25 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, vyasevich, linux-sctp

On Sun, Jul 01, 2012 at 07:44:25PM -0400, Neil Horman wrote:
> On Sun, Jul 01, 2012 at 02:43:19PM -0700, David Miller wrote:
> > From: Neil Horman <nhorman@tuxdriver.com>
> > Date: Sun, 1 Jul 2012 08:47:50 -0400
> > 
> > > Perhaps we could modify the SubmittingPatches document to indicate that an
> > > Acked-by from a subsystem maintainer implicitly confers authority on the
> > > upstream receiver to request reasonable stylistic changes that don't affect the
> > > functionality of the patch in the interests of maintaining coding conventions.
> > 
> > Yes, that would make sense.
> > 
> 
> 
> I'll propose it in a few days.
> Neil
> 
How does this language sound to you?


diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index c379a2a..1eaaeb1 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -414,6 +414,16 @@ the part which affects that maintainer's code.  Judgement should be used here.
 When in doubt people should refer to the original discussion in the mailing
 list archives.
 
+Note that an Acked-by: From a subsystem maintainer on a given patch confers
+upon the tree maintainer integrating the path the authority to carry those Acks
+forward through subsequent versions of a patch, as long as those versions do not
+significantly impact the functionality of the patch.  For example, say the isdn
+subsystem maintainer sends an Acked-by: on version 1 of a patch bound for the
+networking tree.  The networking maintainer then requests that some comments in
+the code be modified to comply with the CodingStyle document.  The networking
+tree maintanier may reapply the subsystem maintainers Acked-by: to the new
+version as no significant changes were made to the patch functionality.
+
 If a person has had the opportunity to comment on a patch, but has not
 provided such comments, you may optionally add a "Cc:" tag to the patch.
 This is the only tag which might be added without an explicit action by the

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-02 12:25             ` Neil Horman
@ 2012-07-03  0:10               ` David Miller
  -1 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-03  0:10 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Mon, 2 Jul 2012 08:25:31 -0400

> On Sun, Jul 01, 2012 at 07:44:25PM -0400, Neil Horman wrote:
>> On Sun, Jul 01, 2012 at 02:43:19PM -0700, David Miller wrote:
>> > From: Neil Horman <nhorman@tuxdriver.com>
>> > Date: Sun, 1 Jul 2012 08:47:50 -0400
>> > 
>> > > Perhaps we could modify the SubmittingPatches document to indicate that an
>> > > Acked-by from a subsystem maintainer implicitly confers authority on the
>> > > upstream receiver to request reasonable stylistic changes that don't affect the
>> > > functionality of the patch in the interests of maintaining coding conventions.
>> > 
>> > Yes, that would make sense.
>> > 
>> 
>> 
>> I'll propose it in a few days.
>> Neil
>> 
> How does this language sound to you?

Looks fine to me.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-03  0:10               ` David Miller
  0 siblings, 0 replies; 66+ messages in thread
From: David Miller @ 2012-07-03  0:10 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, vyasevich, linux-sctp

From: Neil Horman <nhorman@tuxdriver.com>
Date: Mon, 2 Jul 2012 08:25:31 -0400

> On Sun, Jul 01, 2012 at 07:44:25PM -0400, Neil Horman wrote:
>> On Sun, Jul 01, 2012 at 02:43:19PM -0700, David Miller wrote:
>> > From: Neil Horman <nhorman@tuxdriver.com>
>> > Date: Sun, 1 Jul 2012 08:47:50 -0400
>> > 
>> > > Perhaps we could modify the SubmittingPatches document to indicate that an
>> > > Acked-by from a subsystem maintainer implicitly confers authority on the
>> > > upstream receiver to request reasonable stylistic changes that don't affect the
>> > > functionality of the patch in the interests of maintaining coding conventions.
>> > 
>> > Yes, that would make sense.
>> > 
>> 
>> 
>> I'll propose it in a few days.
>> Neil
>> 
> How does this language sound to you?

Looks fine to me.

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-02 12:25             ` Neil Horman
@ 2012-07-03 18:45               ` Jan Ceuleers
  -1 siblings, 0 replies; 66+ messages in thread
From: Jan Ceuleers @ 2012-07-03 18:45 UTC (permalink / raw)
  To: Neil Horman; +Cc: David Miller, netdev, vyasevich, linux-sctp

On 07/02/2012 02:25 PM, Neil Horman wrote:
...

> How does this language sound to you?
...

> +tree maintanier may reapply the subsystem maintainers Acked-by: to the new

s/maintanier/maintainer/

HTH, Jan

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-03 18:45               ` Jan Ceuleers
  0 siblings, 0 replies; 66+ messages in thread
From: Jan Ceuleers @ 2012-07-03 18:45 UTC (permalink / raw)
  To: Neil Horman; +Cc: David Miller, netdev, vyasevich, linux-sctp

On 07/02/2012 02:25 PM, Neil Horman wrote:
...

> How does this language sound to you?
...

> +tree maintanier may reapply the subsystem maintainers Acked-by: to the new

s/maintanier/maintainer/

HTH, Jan

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
  2012-07-03 18:45               ` Jan Ceuleers
@ 2012-07-03 23:42                 ` Neil Horman
  -1 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-03 23:42 UTC (permalink / raw)
  To: Jan Ceuleers; +Cc: David Miller, netdev, vyasevich, linux-sctp

On Tue, Jul 03, 2012 at 08:45:18PM +0200, Jan Ceuleers wrote:
> On 07/02/2012 02:25 PM, Neil Horman wrote:
> ...
> 
> > How does this language sound to you?
> ...
> 
> > +tree maintanier may reapply the subsystem maintainers Acked-by: to the new
> 
> s/maintanier/maintainer/
> 
> HTH, Jan
Thanks Jan, I've fixed it in my local tree, it'll get rolled in the next
version. 
Neil

> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v6] sctp: be more restrictive in transport selection on bundled sacks
@ 2012-07-03 23:42                 ` Neil Horman
  0 siblings, 0 replies; 66+ messages in thread
From: Neil Horman @ 2012-07-03 23:42 UTC (permalink / raw)
  To: Jan Ceuleers; +Cc: David Miller, netdev, vyasevich, linux-sctp

On Tue, Jul 03, 2012 at 08:45:18PM +0200, Jan Ceuleers wrote:
> On 07/02/2012 02:25 PM, Neil Horman wrote:
> ...
> 
> > How does this language sound to you?
> ...
> 
> > +tree maintanier may reapply the subsystem maintainers Acked-by: to the new
> 
> s/maintanier/maintainer/
> 
> HTH, Jan
Thanks Jan, I've fixed it in my local tree, it'll get rolled in the next
version. 
Neil

> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 66+ messages in thread

end of thread, other threads:[~2012-07-03 23:42 UTC | newest]

Thread overview: 66+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-26 20:31 [PATCH] sctp: be mroe restrictive in transport selection on bundled sacks Neil Horman
2012-06-26 20:31 ` Neil Horman
2012-06-27  4:05 ` David Miller
2012-06-27  4:05   ` David Miller
2012-06-27 10:24   ` Neil Horman
2012-06-27 10:24     ` Neil Horman
2012-06-27 13:20     ` Vlad Yasevich
2012-06-27 13:20       ` Vlad Yasevich
2012-06-27 13:22       ` Neil Horman
2012-06-27 13:22         ` Neil Horman
2012-06-27 14:23 ` [PATCH v2] sctp: be more " Neil Horman
2012-06-27 15:10   ` Vlad Yasevich
2012-06-27 17:28     ` Neil Horman
2012-06-27 19:44       ` Vlad Yasevich
2012-06-27 19:44         ` Vlad Yasevich
2012-06-28 15:33         ` Neil Horman
2012-06-28 15:33           ` Neil Horman
2012-06-28 15:58           ` Vlad Yasevich
2012-06-28 15:58             ` Vlad Yasevich
2012-06-28 18:07             ` Neil Horman
2012-06-28 18:07               ` Neil Horman
2012-06-28 18:22               ` Vlad Yasevich
2012-06-28 18:22                 ` Vlad Yasevich
2012-06-28 18:36                 ` Neil Horman
2012-06-28 18:36                   ` Neil Horman
2012-06-28 20:14                 ` Neil Horman
2012-06-28 20:14                   ` Neil Horman
2012-06-29 16:34 ` [PATCH v3] " Neil Horman
2012-06-29 18:29   ` Vlad Yasevich
2012-06-29 18:43     ` Neil Horman
2012-06-29 19:15       ` Vlad Yasevich
2012-06-29 19:21         ` Neil Horman
2012-06-29 19:24 ` [PATCH v4] " Neil Horman
2012-06-29 19:24   ` Neil Horman
2012-06-29 20:15 ` [PATCH v5] " Neil Horman
2012-06-29 20:15   ` Neil Horman
2012-06-29 20:19   ` Vlad Yasevich
2012-06-29 20:19     ` Vlad Yasevich
2012-06-29 23:34   ` David Miller
2012-06-29 23:34     ` David Miller
2012-06-30 12:26     ` Neil Horman
2012-06-30 12:26       ` Neil Horman
2012-07-01  0:38       ` David Miller
2012-07-01  0:38         ` David Miller
2012-06-30 13:04 ` [PATCH v6] " Neil Horman
2012-06-30 13:04   ` Neil Horman
2012-07-01  0:39   ` David Miller
2012-07-01  0:39     ` David Miller
2012-07-01  3:17     ` Vlad Yasevich
2012-07-01  3:17       ` Vlad Yasevich
2012-07-01  5:44       ` David Miller
2012-07-01  5:44         ` David Miller
2012-07-01 12:47     ` Neil Horman
2012-07-01 12:47       ` Neil Horman
2012-07-01 21:43       ` David Miller
2012-07-01 21:43         ` David Miller
2012-07-01 23:44         ` Neil Horman
2012-07-01 23:44           ` Neil Horman
2012-07-02 12:25           ` Neil Horman
2012-07-02 12:25             ` Neil Horman
2012-07-03  0:10             ` David Miller
2012-07-03  0:10               ` David Miller
2012-07-03 18:45             ` Jan Ceuleers
2012-07-03 18:45               ` Jan Ceuleers
2012-07-03 23:42               ` Neil Horman
2012-07-03 23:42                 ` Neil Horman

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.