[PATCH 28/43]: Make computation of X_recv conform to TFRC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[CCID3]: Make computation of X_recv conform to TFRC

The computation of X_recv does currently not conform to TFRC/RFC 3448,
since this specification requires that X_recv be computed over the last
R_m seconds (sec. 6.2).  
The code, in contrast, computes X_recv over the time the last feedback was 
sent. This results in sending wrong estimates of X_recv, making it impossible
for the sender to find its allowed sending rate.

The patch
 * explicitly distinguishes the types of feedback (using an enum);
 * uses previous value of X_recv when sending feedback due to a parameter change;
 * makes all state changes local to ccid3_hc_tx_packet_recv;
 * assigns feedback type according to incident (previously only used flag `do_feedback').

Detailed justifications and explanations are provided online at
http://www.erg.abdn.ac.uk/users/gerrit/dccp/docs/ccid3_packet_reception/#8._Computing_X_recv_ 

As a result, not only is the computation of X_recv more accurate, but also the
feedback handling is much less clumsy as before: states are clearly separated.

Signed-off-by: Gerrit Renker <gerrit@xxxxxxxxxxxxxx>
---
 net/dccp/ccids/ccid3.c |   45 +++++++++++++++++++++++++++++++--------------
 net/dccp/ccids/ccid3.h |   10 +++++++++-
 2 files changed, 40 insertions(+), 15 deletions(-)

--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -125,13 +125,21 @@ static inline struct ccid3_hc_tx_sock *c
 	return ccid3_tx_priv;
 }
 
-/* TFRC receiver states */
+/* CCID3 receiver states */
 enum ccid3_hc_rx_states {
 	TFRC_RSTATE_NO_DATA = 1,
 	TFRC_RSTATE_DATA,
 	TFRC_RSTATE_TERM    = 127,
 };
 
+/* CCID3 feedback types */
+enum ccid3_fback_type {
+	FBACK_NONE = 0,
+	FBACK_INITIAL,
+	FBACK_PERIODIC,
+	FBACK_PARAM_CHANGE
+};
+
 /** struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket
  *
  *  @ccid3hcrx_last_counter  -  Tracks window counter (RFC 4342, 8.1)
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -720,30 +720,46 @@ static inline void ccid3_hc_rx_update_s(
 		TFRC_EWMA(hcrx->ccid3hcrx_s, len, 9);
 }
 
-static void ccid3_hc_rx_send_feedback(struct sock *sk, struct sk_buff *skb)
+static void ccid3_hc_rx_send_feedback(struct sock *sk, struct sk_buff *skb,
+				      enum ccid3_fback_type fbtype)
 {
 	struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct timeval now, t_recv;
 	suseconds_t delta = 0;
 
+	if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_TERM))
+		return;
+
 	do_gettimeofday(&now);
 
-	switch (hcrx->ccid3hcrx_state) {
-	case TFRC_RSTATE_NO_DATA:
+	switch (fbtype) {
+	case FBACK_INITIAL:
 		hcrx->ccid3hcrx_x_recv = 0;
 		hcrx->ccid3hcrx_pinv   = ~0U;	/* see RFC 4342, 8.5 */
-		ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
 		break;
-	case TFRC_RSTATE_DATA:
+	case FBACK_PARAM_CHANGE:
+		/*
+		 * When parameters change (new loss or p > p_prev), we do not
+		 * have a reliable estimate for R_m of [RFC 3448, 6.2] and so
+		 * need to  reuse the previous value of X_recv. However, when
+		 * X_recv was 0 (due to early loss), this would kill X down to
+		 * s/t_mbi (i.e. one packet in 64 seconds).
+		 * To avoid such drastic reduction, we approximate X_recv as
+		 * the number of bytes since last feedback.
+		 * This is a safe fallback, since X is bounded above by X_calc.
+		 */
+		if (hcrx->ccid3hcrx_x_recv > 0)
+			break;
+		/* fall through */
+	case FBACK_PERIODIC:
 		delta = timeval_delta(&now,
 				      &hcrx->ccid3hcrx_tstamp_last_feedback);
 		DCCP_BUG_ON(delta < 0);
 		hcrx->ccid3hcrx_x_recv =
 			scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
 		break;
-	case TFRC_RSTATE_TERM:
-		DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
+	default:
 		return;
 	}
 	ccid3_pr_debug("Interval %ldusec, X_recv=%u, 1/p=%u\n", (long)delta,
@@ -838,16 +854,17 @@ static u32 ccid3_first_li(struct sock *s
 static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
 {
 	struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+	enum   ccid3_fback_type  do_feedback = FBACK_NONE;
 	u32 sample, ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp,
 	    payload_size = skb->len - dccp_hdr(skb)->dccph_doff * 4;
-	u8  is_data_packet = dccp_data_packet(skb), do_feedback = 0;
+	u8  is_data_packet = dccp_data_packet(skb);
 
 	spin_lock(&hcrx->ccid3hcrx_hist.lock);
 
 	if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)) {
-		/* Handle initial feedback */
 		if (is_data_packet) {
-			do_feedback = 1;
+			do_feedback = FBACK_INITIAL;
+			ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
 			ccid3_hc_rx_update_s(hcrx, payload_size);
 		}
 		goto update_records;
@@ -868,7 +885,7 @@ static void ccid3_hc_rx_packet_recv(stru
 	    tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist,
 				&hcrx->ccid3hcrx_li_hist,
 				skb, ndp, ccid3_first_li, sk) ) {
-		do_feedback = 1;
+		do_feedback = FBACK_PARAM_CHANGE;
 		goto sending_feedback;
 	}
 
@@ -896,12 +913,12 @@ static void ccid3_hc_rx_packet_recv(stru
 		 * Step (3) of [RFC 3448, 6.1]: Recompute I_mean and, if I_mean
 		 * has decreased (resp. p has increased), send feedback now.
 		 */
-		do_feedback = 1;
+		do_feedback = FBACK_PARAM_CHANGE;
 
 
 	/* check if the periodic once-per-RTT feedback is due; RFC 4342, 10.3 */
 	if (SUB16(dccp_hdr(skb)->dccph_ccval, hcrx->ccid3hcrx_last_counter) > 3)
-		do_feedback = 1;
+		do_feedback = FBACK_PERIODIC;
 
 update_records:
 	tfrc_rx_hist_update(&hcrx->ccid3hcrx_hist, skb, ndp);
@@ -910,7 +927,7 @@ sending_feedback:
 	spin_unlock(&hcrx->ccid3hcrx_hist.lock);
 
 	if (do_feedback)
-		ccid3_hc_rx_send_feedback(sk, skb);
+		ccid3_hc_rx_send_feedback(sk, skb, do_feedback);
 }
 
 static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
-
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [IETF DCCP]     [Linux Networking]     [Git]     [Security]     [Linux Assembly]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux