From owner-svn-src-all@FreeBSD.ORG Tue Oct 26 19:08:26 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 741141065694; Tue, 26 Oct 2010 19:08:26 +0000 (UTC) (envelope-from rrs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 61C2D8FC1E; Tue, 26 Oct 2010 19:08:26 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o9QJ8Qch063346; Tue, 26 Oct 2010 19:08:26 GMT (envelope-from rrs@svn.freebsd.org) Received: (from rrs@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o9QJ8QOL063341; Tue, 26 Oct 2010 19:08:26 GMT (envelope-from rrs@svn.freebsd.org) Message-Id: <201010261908.o9QJ8QOL063341@svn.freebsd.org> From: Randall Stewart Date: Tue, 26 Oct 2010 19:08:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r214394 - stable/8/sys/netinet X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Oct 2010 19:08:26 -0000 Author: rrs Date: Tue Oct 26 19:08:26 2010 New Revision: 214394 URL: http://svn.freebsd.org/changeset/base/214394 Log: MFC:210599 PR SCTP Bugs. Basically a full sized frame of PR SCTP FWD-TSN's would not be sent and thus cause a stalled connection. Also the rwnd Calculation was also off on the receiver side for PR-SCTP. Modified: stable/8/sys/netinet/sctp_indata.c stable/8/sys/netinet/sctp_output.c stable/8/sys/netinet/sctp_structs.h stable/8/sys/netinet/sctp_timer.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) Modified: stable/8/sys/netinet/sctp_indata.c ============================================================================== --- stable/8/sys/netinet/sctp_indata.c Tue Oct 26 19:06:31 2010 (r214393) +++ stable/8/sys/netinet/sctp_indata.c Tue Oct 26 19:08:26 2010 (r214394) @@ -91,8 +91,10 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, st * take out what has NOT been put on socket queue and we yet hold * for putting up. */ - calc = sctp_sbspace_sub(calc, (uint32_t) asoc->size_on_reasm_queue); - calc = sctp_sbspace_sub(calc, (uint32_t) asoc->size_on_all_streams); + calc = sctp_sbspace_sub(calc, (uint32_t) (asoc->size_on_reasm_queue + + asoc->cnt_on_reasm_queue * MSIZE)); + calc = sctp_sbspace_sub(calc, (uint32_t) (asoc->size_on_all_streams + + asoc->cnt_on_all_streams * MSIZE)); if (calc == 0) { /* out of space */ @@ -3322,6 +3324,10 @@ sctp_strike_gap_ack_chunks(struct sctp_t if (tp1->sent >= SCTP_DATAGRAM_RESEND) { /* either a RESEND, ACKED, or MARKED */ /* skip */ + if (tp1->sent == SCTP_FORWARD_TSN_SKIP) { + /* Continue strikin FWD-TSN chunks */ + tp1->rec.data.fwd_tsn_cnt++; + } tp1 = TAILQ_NEXT(tp1, sctp_next); continue; } @@ -3707,7 +3713,6 @@ sctp_try_advance_peer_ack_point(struct s tp1 = TAILQ_FIRST(&asoc->sent_queue); while (tp1) { if (tp1->sent != SCTP_FORWARD_TSN_SKIP && - tp1->sent != SCTP_DATAGRAM_ACKED && tp1->sent != SCTP_DATAGRAM_RESEND) { /* no chance to advance, out of here */ break; @@ -3763,8 +3768,7 @@ sctp_try_advance_peer_ack_point(struct s * the chunk, advance our peer ack point and we can check * the next chunk. */ - if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) || - (tp1->sent == SCTP_DATAGRAM_ACKED)) { + if (tp1->sent == SCTP_FORWARD_TSN_SKIP) { /* advance PeerAckPoint goes forward */ if (compare_with_wrap(tp1->rec.data.TSN_seq, asoc->advanced_peer_ack_point, @@ -3905,7 +3909,7 @@ sctp_express_handle_sack(struct sctp_tcb } else if (asoc->last_acked_seq == cumack) { /* Window update sack */ asoc->peers_rwnd = sctp_sbspace_sub(rwnd, - (uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); + (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { /* SWS sender side engages */ asoc->peers_rwnd = 0; @@ -4189,7 +4193,7 @@ sctp_express_handle_sack(struct sctp_tcb } /* RWND update */ asoc->peers_rwnd = sctp_sbspace_sub(rwnd, - (uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); + (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { /* SWS sender side engages */ asoc->peers_rwnd = 0; @@ -4404,10 +4408,8 @@ again: asoc->nonce_resync_tsn = asoc->advanced_peer_ack_point; } else if (lchk) { /* try to FR fwd-tsn's that get lost too */ - lchk->rec.data.fwd_tsn_cnt++; - if (lchk->rec.data.fwd_tsn_cnt > 3) { + if (lchk->rec.data.fwd_tsn_cnt >= 3) { send_forward_tsn(stcb, asoc); - lchk->rec.data.fwd_tsn_cnt = 0; } } } @@ -5188,10 +5190,10 @@ done_with_it: /* Adjust and set the new rwnd value */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, - asoc->peers_rwnd, asoc->total_flight, (asoc->sent_queue_cnt * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)), a_rwnd); + asoc->peers_rwnd, asoc->total_flight, (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)), a_rwnd); } asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd, - (uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); + (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { /* SWS sender side engages */ asoc->peers_rwnd = 0; @@ -5314,6 +5316,7 @@ again: } if (compare_with_wrap(asoc->advanced_peer_ack_point, old_adv_peer_ack_point, MAX_TSN)) { + send_forward_tsn(stcb, asoc); /* * ECN Nonce: Disable Nonce Sum check when @@ -5323,10 +5326,8 @@ again: asoc->nonce_resync_tsn = asoc->advanced_peer_ack_point; } else if (lchk) { /* try to FR fwd-tsn's that get lost too */ - lchk->rec.data.fwd_tsn_cnt++; - if (lchk->rec.data.fwd_tsn_cnt > 3) { + if (lchk->rec.data.fwd_tsn_cnt >= 3) { send_forward_tsn(stcb, asoc); - lchk->rec.data.fwd_tsn_cnt = 0; } } } Modified: stable/8/sys/netinet/sctp_output.c ============================================================================== --- stable/8/sys/netinet/sctp_output.c Tue Oct 26 19:06:31 2010 (r214393) +++ stable/8/sys/netinet/sctp_output.c Tue Oct 26 19:08:26 2010 (r214394) @@ -6580,6 +6580,8 @@ sctp_clean_up_ctl(struct sctp_tcb *stcb, chk->data = NULL; } asoc->ctrl_queue_cnt--; + if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) + asoc->fwd_tsn_cnt--; sctp_free_a_chunk(stcb, chk); } else if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) { /* special handling, we must look into the param */ @@ -7800,7 +7802,7 @@ again_one_more_time: } else omtu = 0; /* Here we do NOT factor the r_mtu */ - if ((chk->send_size < (int)(mtu - omtu)) || + if ((chk->send_size <= (int)(mtu - omtu)) || (chk->flags & CHUNK_FLAGS_FRAGMENT_OK)) { /* * We probably should glom the mbuf chain @@ -9705,6 +9707,7 @@ send_forward_tsn(struct sctp_tcb *stcb, if (chk == NULL) { return; } + asoc->fwd_tsn_cnt++; chk->copy_by_ref = 0; chk->rec.chunk_id.id = SCTP_FORWARD_CUM_TSN; chk->rec.chunk_id.can_take_data = 0; @@ -9736,8 +9739,8 @@ sctp_fill_in_rest: unsigned int cnt_of_skipped = 0; TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { - if ((at->sent != SCTP_FORWARD_TSN_SKIP) && - (at->sent != SCTP_DATAGRAM_ACKED)) { + if ((at->sent != SCTP_FORWARD_TSN_SKIP) /* && (at->sent != + SCTP_DATAGRAM_ACKED) */ ) { /* no more to look at */ break; } Modified: stable/8/sys/netinet/sctp_structs.h ============================================================================== --- stable/8/sys/netinet/sctp_structs.h Tue Oct 26 19:06:31 2010 (r214393) +++ stable/8/sys/netinet/sctp_structs.h Tue Oct 26 19:08:26 2010 (r214394) @@ -869,6 +869,7 @@ struct sctp_association { unsigned int size_on_reasm_queue; unsigned int cnt_on_reasm_queue; + unsigned int fwd_tsn_cnt; /* amount of data (bytes) currently in flight (on all destinations) */ unsigned int total_flight; /* Total book size in flight */ Modified: stable/8/sys/netinet/sctp_timer.c ============================================================================== --- stable/8/sys/netinet/sctp_timer.c Tue Oct 26 19:06:31 2010 (r214393) +++ stable/8/sys/netinet/sctp_timer.c Tue Oct 26 19:08:26 2010 (r214394) @@ -545,7 +545,7 @@ static void sctp_backoff_on_timeout(struct sctp_tcb *stcb, struct sctp_nets *net, int win_probe, - int num_marked) + int num_marked, int num_abandoned) { if (net->RTO == 0) { net->RTO = stcb->asoc.minrto; @@ -554,7 +554,7 @@ sctp_backoff_on_timeout(struct sctp_tcb if (net->RTO > stcb->asoc.maxrto) { net->RTO = stcb->asoc.maxrto; } - if ((win_probe == 0) && num_marked) { + if ((win_probe == 0) && (num_marked || num_abandoned)) { /* We don't apply penalty to window probe scenarios */ /* JRS - Use the congestion control given in the CC module */ stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net); @@ -612,7 +612,8 @@ sctp_mark_all_for_resend(struct sctp_tcb struct sctp_nets *net, struct sctp_nets *alt, int window_probe, - int *num_marked) + int *num_marked, + int *num_abandoned) { /* @@ -621,10 +622,11 @@ sctp_mark_all_for_resend(struct sctp_tcb * We only mark chunks that have been outstanding long enough to * have received feed-back. */ - struct sctp_tmit_chunk *chk, *tp2, *could_be_sent = NULL; + struct sctp_tmit_chunk *chk, *tp2; struct sctp_nets *lnets; struct timeval now, min_wait, tv; int cur_rtt; + int cnt_abandoned; int audit_tf, num_mk, fir; unsigned int cnt_mk; uint32_t orig_flight, orig_tf; @@ -680,6 +682,7 @@ sctp_mark_all_for_resend(struct sctp_tcb net->fast_retran_ip = 0; /* Now on to each chunk */ + cnt_abandoned = 0; num_mk = cnt_mk = 0; tsnfirst = tsnlast = 0; #ifndef INVARIANTS @@ -768,6 +771,7 @@ start_again: chk, (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), SCTP_SO_NOT_LOCKED); + cnt_abandoned++; } continue; } @@ -780,6 +784,7 @@ start_again: chk, (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), SCTP_SO_NOT_LOCKED); + cnt_abandoned++; } continue; } @@ -841,9 +846,11 @@ start_again: if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 1) { chk->no_fr_allowed = 1; } +#ifdef THIS_SHOULD_NOT_BE_DONE } else if (chk->sent == SCTP_DATAGRAM_ACKED) { /* remember highest acked one */ could_be_sent = chk; +#endif } if (chk->sent == SCTP_DATAGRAM_RESEND) { cnt_mk++; @@ -870,6 +877,7 @@ start_again: } #endif *num_marked = num_mk; + *num_abandoned = cnt_abandoned; /* * Now check for a ECN Echo that may be stranded And include the * cnt_mk'd to have all resends in the control queue. @@ -890,12 +898,14 @@ start_again: atomic_add_int(&alt->ref_count, 1); } } +#ifdef THIS_SHOULD_NOT_BE_DONE if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { /* fix it so we retransmit the highest acked anyway */ sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); cnt_mk++; could_be_sent->sent = SCTP_DATAGRAM_RESEND; } +#endif if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { #ifdef INVARIANTS SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n", @@ -996,7 +1006,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, struct sctp_nets *net) { struct sctp_nets *alt; - int win_probe, num_mk; + int win_probe, num_mk, num_abandoned; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); @@ -1055,8 +1065,10 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, } else { /* CMT is OFF */ alt = sctp_find_alternate_net(stcb, net, 0); } - - (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, &num_mk); + num_mk = 0; + num_abandoned = 0; + (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, + &num_mk, &num_abandoned); /* FR Loss recovery just ended with the T3. */ stcb->asoc.fast_retran_loss_recovery = 0; @@ -1070,7 +1082,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; /* Backoff the timer and cwnd */ - sctp_backoff_on_timeout(stcb, net, win_probe, num_mk); + sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); if (win_probe == 0) { /* We don't do normal threshold management on window probes */ if (sctp_threshold_management(inp, stcb, net, @@ -1221,7 +1233,7 @@ sctp_t1init_timer(struct sctp_inpcb *inp return (1); } stcb->asoc.dropped_special_cnt = 0; - sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0); + sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0, 0); if (stcb->asoc.initial_init_rto_max < net->RTO) { net->RTO = stcb->asoc.initial_init_rto_max; } @@ -1302,7 +1314,7 @@ sctp_cookie_timer(struct sctp_inpcb *inp * an alternate */ stcb->asoc.dropped_special_cnt = 0; - sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0); + sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); if (alt != cookie->whoTo) { sctp_free_remote_addr(cookie->whoTo); @@ -1347,7 +1359,7 @@ sctp_strreset_timer(struct sctp_inpcb *i * cleared theshold management now lets backoff the address & select * an alternate */ - sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0); + sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); sctp_free_remote_addr(strrst->whoTo); strrst->whoTo = alt; @@ -1426,7 +1438,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp * cleared threshold management, so now backoff the net and * select an alternate */ - sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0); + sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0); if (asconf->whoTo != alt) { sctp_free_remote_addr(asconf->whoTo); @@ -1643,7 +1655,7 @@ sctp_heartbeat_timer(struct sctp_inpcb * net->ro._s_addr = NULL; net->src_addr_selected = 0; } - sctp_backoff_on_timeout(stcb, net, 1, 0); + sctp_backoff_on_timeout(stcb, net, 1, 0, 0); } /* Zero PBA, if it needs it */ if (net->partial_bytes_acked) {