ccid-3: Rate Mismatch Controller

This provides a proof-of-concept implementation of the Rate Mismatch Controller
algorithm presented by Luca De Cicco and Saverio Masceriolo in their 2009 paper
	Luca De Cicco, Saverio Mascolo
	"A Mismatch Controller for Implementing
	 High-Speed Rate-based Transport Protocols"
	Proceedings of ICNP 2009

This patch is rudimentary and for use in combination with the 'xset' patch which
sets a fixed sending rate X_set. 
By passing the expected sending rate X_set as module parameter, and by observing
the effectively achieved rate, one can evaluate the efficiency of the algorithm.

Notes:
------
 1) The patch allows to test jiffy-based computation of rates as well as
    a variant based on ktime_t. The latter gives more accurate results.
 2) There are additional modifications which allow testing with different values
    of HZ and clocksource=..., where the sampled RTT is often rounded down to 0.
    This use of CCID-3 is not safe, since a zero RTT may cause other problems
    elsewhere. When using a low clock resolution, 0-RTT induced bugs may surface
    (which is why low timer resolution is still disabled).
---
 net/dccp/ccid.c        |    5 ++++
 net/dccp/ccids/ccid3.c |   53 ++++++++++++++++++++++++++++++++-----------------
 net/dccp/ccids/ccid3.h |   11 ++++++++++
 3 files changed, 51 insertions(+), 18 deletions(-)

--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -209,7 +209,12 @@ int __init ccid_initialize_builtins(void
 		printk(KERN_ERR "DCCP: clocksource too coarse (%ld usec), "
 				"need %u-usec resolution\n",
 		       tp.tv_nsec/NSEC_PER_USEC, DCCP_TIME_RESOLUTION);
+		/*
+		 * Disable this to test with lower values of HZ
+		 * Use with lots of caution.
+		 *
 		return -ESOCKTNOSUPPORT;
+		 */
 	}
 #endif
 	err = tfrc_lib_init();
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -258,8 +258,12 @@ static int ccid3_hc_tx_send_packet(struc
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+#if _RMC_USE_JIFFIES
+	unsigned long now = jiffies;
+#else
 	ktime_t now = ktime_get_real();
 	s64 delay;
+#endif
 
 	/*
 	 * This function is called only for Data and DataAck packets. Sending
@@ -273,10 +277,7 @@ static int ccid3_hc_tx_send_packet(struc
 		sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies +
 			       usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
 		hc->tx_last_win_count	= 0;
-		hc->tx_t_last_win_count = now;
-
-		/* Set t_0 for initial packet */
-		hc->tx_t_nom = now;
+		hc->tx_t_last_win_count = ktime_get_real();
 
 		/*
 		 * Use initial RTT sample when available: recommended by erratum
@@ -287,7 +288,7 @@ static int ccid3_hc_tx_send_packet(struc
 			ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt);
 			hc->tx_rtt  = dp->dccps_syn_rtt;
 			hc->tx_x    = rfc3390_initial_rate(sk);
-			hc->tx_t_ld = now;
+			hc->tx_t_ld = hc->tx_t_last_win_count;
 		} else {
 			/*
 			 * Sender does not have RTT sample:
@@ -300,6 +301,14 @@ static int ccid3_hc_tx_send_packet(struc
 			hc->tx_x <<= 6;
 		}
 
+		/* Compute initial send credit, valid from now..now+RTT */
+#if _RMC_USE_JIFFIES
+		hc->tx_rmc.t_k = now + usecs_to_jiffies(hc->tx_rtt);
+#else
+		hc->tx_rmc.t_k = ktime_add_us(now, hc->tx_rtt);
+#endif
+		hc->tx_rmc.bytes_to_send = div_u64(hc->tx_x * hc->tx_rtt, USEC_PER_SEC << 6);
+
 		/* Compute t_ipi = s / X */
 		hc->tx_s = ccid3_hc_tx_measure_packet_size(sk, skb->len);
 		if (xset)
@@ -310,20 +319,24 @@ static int ccid3_hc_tx_send_packet(struc
 		hc->tx_r_sqmean = tfrc_scaled_sqrt(hc->tx_rtt);
 
 	} else {
-		delay = ktime_us_delta(hc->tx_t_nom, now);
-		ccid3_pr_debug("delay=%ld\n", (long)delay);
-		/*
-		 *	Scheduling of packet transmissions [RFC 3448, 4.6]
-		 *
-		 * if (t_now > t_nom - delta)
-		 *       // send the packet now
-		 * else
-		 *       // send the packet in (t_nom - t_now) milliseconds.
-		 */
-		if (delay >= TFRC_T_DELTA)
-			return (u32)delay / USEC_PER_MSEC;
+#if _RMC_USE_JIFFIES
+		if (time_after(now, hc->tx_rmc.t_k)) {
+			u32 delta_ms = jiffies_to_msecs(now - hc->tx_rmc.t_k);
+			u64 bdelta   = div_u64(delta_ms * hc->tx_x, MSEC_PER_SEC << 6);
+#else
+		delay = ktime_us_delta(now, hc->tx_rmc.t_k);
+
+		if (delay >= 1000) {
+			u64 bdelta = div_u64(hc->tx_x * delay, USEC_PER_SEC << 6);
+#endif
+			hc->tx_rmc.bytes_to_send += bdelta;
+			hc->tx_rmc.t_k = now;
+		}
+
+		if (skb->len > hc->tx_rmc.bytes_to_send)
+			return DIV_ROUND_UP(hc->tx_t_ipi, USEC_PER_MSEC);
 
-		ccid3_hc_tx_update_win_count(hc, now);
+		ccid3_hc_tx_update_win_count(hc, ktime_get_real());
 	}
 
 	/* prepare to send now (add options etc.) */
@@ -339,6 +352,8 @@ static void ccid3_hc_tx_packet_sent(stru
 {
 	struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
 
+	hc->tx_rmc.bytes_to_send -= len;
+
 	/* Changes to s will become effective the next time X is computed */
 	hc->tx_s = ccid3_hc_tx_measure_packet_size(sk, len);
 
@@ -688,6 +703,8 @@ static u32 ccid3_first_li(struct sock *s
 	    rtt = tfrc_rx_hist_rtt(&hc->rx_hist), x_recv, p;
 	u64 fval;
 
+	if (rtt == 0)
+		rtt = 1;
 	/*
 	 * rfc3448bis-06, 6.3.1: First data packet(s) are marked or lost. Set p
 	 * to give the equivalent of X_target = s/(2*R). Thus fval = 2 and so p
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -67,6 +67,8 @@ enum ccid3_options {
 	TFRC_OPT_RECEIVE_RATE	 = 194,
 };
 
+/* Rate Mismatch Controller: set to 0 to use ktime_t, 1 to use jiffies */
+#define _RMC_USE_JIFFIES 0
 /**
  * struct ccid3_hc_tx_sock - CCID3 sender half-connection socket
  * @tx_x:		  Current sending rate in 64 * bytes per second
@@ -85,6 +87,7 @@ enum ccid3_options {
  * @tx_no_feedback_timer: Handle to no feedback timer
  * @tx_t_ld:		  Time last doubled during slow start
  * @tx_t_nom:		  Nominal send time of next packet
+ * @tx_rmc:		  Rate Mismatch Controller state
  * @tx_hist:		  Packet history
  */
 struct ccid3_hc_tx_sock {
@@ -103,6 +106,14 @@ struct ccid3_hc_tx_sock {
 	struct timer_list		tx_no_feedback_timer;
 	ktime_t				tx_t_ld;
 	ktime_t				tx_t_nom;
+	struct	{
+#if _RMC_USE_JIFFIES
+		unsigned long	t_k;
+#else
+		ktime_t		t_k;
+#endif
+		u32		bytes_to_send;
+	} tx_rmc;
 	struct tfrc_tx_hist_entry	*tx_hist;
 };
 
