summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_output.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2011-01-29 19:55:29 +0000
committerrrs <rrs@FreeBSD.org>2011-01-29 19:55:29 +0000
commit181e76925b50ce041a6d66c7cd4ae9ab59f899fe (patch)
tree884eed6be8a57a18544af44bfa09d9cf42de648d /sys/netinet/sctp_output.c
parent48530618fa80ecf1ff9a984c3bcc14a07bb41986 (diff)
downloadFreeBSD-src-181e76925b50ce041a6d66c7cd4ae9ab59f899fe.zip
FreeBSD-src-181e76925b50ce041a6d66c7cd4ae9ab59f899fe.tar.gz
Fixes to ECN in SCTP.
1) ECN was on an association basis, this is incorrect and will not work with CMT or for that matter if the user is sending to multiple addresses. This commit makes ECN on a per path basis. 2) Adopt the new format for the ECN internet draft. This also maintains compatability with old format chunks as well. 3) Keep track of the real time of a RTT down to micro seconds. For some future conditional features (for like a data center this is good information to have). MFC after: 1 month
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r--sys/netinet/sctp_output.c77
1 files changed, 58 insertions, 19 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 480c88e..0651054 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -7274,7 +7274,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
* fomulate and send the low level chunks. Making sure to combine
* any control in the control chunk queue also.
*/
- struct sctp_nets *net, *start_at, *old_start_at = NULL;
+ struct sctp_nets *net, *start_at, *sack_goes_to = NULL, *old_start_at = NULL;
struct mbuf *outchain, *endoutchain;
struct sctp_tmit_chunk *chk, *nchk;
@@ -7327,10 +7327,12 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
no_data_chunks = 0;
/* Nothing to possible to send? */
- if (TAILQ_EMPTY(&asoc->control_send_queue) &&
+ if ((TAILQ_EMPTY(&asoc->control_send_queue) ||
+ (asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) &&
TAILQ_EMPTY(&asoc->asconf_send_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+nothing_to_send:
*reason_code = 9;
return (0);
}
@@ -7342,6 +7344,21 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
no_data_chunks = 1;
}
}
+ if (stcb->asoc.ecn_echo_cnt_onq) {
+ /* Record where a sack goes, if any */
+ if (no_data_chunks &&
+ (asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) {
+ /* Nothing but ECNe to send - we don't do that */
+ goto nothing_to_send;
+ }
+ TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
+ if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) ||
+ (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK)) {
+ sack_goes_to = chk->whoTo;
+ break;
+ }
+ }
+ }
max_rwnd_per_dest = ((asoc->peers_rwnd + asoc->total_flight) / asoc->numnets);
if (stcb->sctp_socket)
max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets;
@@ -7685,6 +7702,28 @@ again_one_more_time:
/************************/
/* Now first lets go through the control queue */
TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) {
+ if ((sack_goes_to) &&
+ (chk->rec.chunk_id.id == SCTP_ECN_ECHO) &&
+ (chk->whoTo != sack_goes_to)) {
+ /*
+ * if we have a sack in queue, and we are
+ * looking at an ecn echo that is NOT queued
+ * to where the sack is going..
+ */
+ if (chk->whoTo == net) {
+ /*
+ * Don't transmit it to where its
+ * going (current net)
+ */
+ continue;
+ } else if (sack_goes_to == net) {
+ /*
+ * But do transmit it to this
+ * address
+ */
+ goto skip_net_check;
+ }
+ }
if (chk->whoTo != net) {
/*
* No, not sent to the network we are
@@ -7692,6 +7731,7 @@ again_one_more_time:
*/
continue;
}
+ skip_net_check:
if (chk->data == NULL) {
continue;
}
@@ -10761,11 +10801,19 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
- if (chk->rec.chunk_id.id == SCTP_ECN_ECHO) {
+ if ((chk->rec.chunk_id.id == SCTP_ECN_ECHO) && (net == chk->whoTo)) {
/* found a previous ECN_ECHO update it if needed */
+ uint32_t cnt, ctsn;
+
ecne = mtod(chk->data, struct sctp_ecne_chunk *);
- ecne->tsn = htonl(high_tsn);
- SCTP_STAT_INCR(sctps_queue_upd_ecne);
+ ctsn = ntohl(ecne->tsn);
+ if (SCTP_TSN_GT(high_tsn, ctsn)) {
+ ecne->tsn = htonl(high_tsn);
+ cnt = ntohl(ecne->num_pkts_since_cwr);
+ cnt++;
+ ecne->num_pkts_since_cwr = htonl(cnt);
+ SCTP_STAT_INCR(sctps_queue_upd_ecne);
+ }
return;
}
}
@@ -10797,7 +10845,8 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
ecne->ch.chunk_flags = 0;
ecne->ch.chunk_length = htons(sizeof(struct sctp_ecne_chunk));
ecne->tsn = htonl(high_tsn);
- TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next);
+ ecne->num_pkts_since_cwr = htonl(1);
+ TAILQ_INSERT_HEAD(&stcb->asoc.control_send_queue, chk, sctp_next);
asoc->ctrl_queue_cnt++;
}
@@ -10975,7 +11024,7 @@ jump_out:
}
void
-sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn)
+sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, uint8_t override)
{
struct sctp_association *asoc;
struct sctp_cwr_chunk *cwr;
@@ -10983,17 +11032,7 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn)
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
- TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
- if (chk->rec.chunk_id.id == SCTP_ECN_CWR) {
- /* found a previous ECN_CWR update it if needed */
- cwr = mtod(chk->data, struct sctp_cwr_chunk *);
- if (SCTP_TSN_GT(high_tsn, ntohl(cwr->tsn))) {
- cwr->tsn = htonl(high_tsn);
- }
- return;
- }
- }
- /* nope could not find one to update so we must build one */
+
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
return;
@@ -11016,7 +11055,7 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn)
atomic_add_int(&chk->whoTo->ref_count, 1);
cwr = mtod(chk->data, struct sctp_cwr_chunk *);
cwr->ch.chunk_type = SCTP_ECN_CWR;
- cwr->ch.chunk_flags = 0;
+ cwr->ch.chunk_flags = override;
cwr->ch.chunk_length = htons(sizeof(struct sctp_cwr_chunk));
cwr->tsn = htonl(high_tsn);
TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next);
OpenPOWER on IntegriCloud