Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12472b41 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [SUNHME]: Fix for sunhme failures on x86
  [XFRM] xfrm_user: Better validation of user templates.
  [DCCP] tfrc: Binary search for reverse TFRC lookup
  [DCCP] ccid3: Deprecate TFRC_SMALLEST_P
  [DCCP] tfrc: Identify TFRC table limits and simplify code
  [DCCP] tfrc: Add protection against invalid parameters to TFRC routines
  [DCCP] tfrc: Fix small error in reverse lookup of p for given f(p)
  [DCCP] tfrc: Document boundaries and limits of the TFRC lookup table
  [DCCP] ccid3: Fix warning message about illegal ACK
  [DCCP] ccid3: Fix bug in calculation of send rate
  [DCCP]: Fix BUG in retransmission delay calculation
  [DCCP]: Use higher RTO default for CCID3
parents a79f43a5 ef9467f8
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -3012,6 +3012,11 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
#endif
#endif


	err = -ENODEV;
	err = -ENODEV;

	if (pci_enable_device(pdev))
		goto err_out;
	pci_set_master(pdev);

	if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) {
	if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) {
		qp = quattro_pci_find(pdev);
		qp = quattro_pci_find(pdev);
		if (qp == NULL)
		if (qp == NULL)
+33 −0
Original line number Original line Diff line number Diff line
@@ -89,4 +89,37 @@ config IP_DCCP_CCID3_DEBUG
	    parameter to 0 or 1.
	    parameter to 0 or 1.


	    If in doubt, say N.
	    If in doubt, say N.

config IP_DCCP_CCID3_RTO
	  int "Use higher bound for nofeedback timer"
	  default 100
	  depends on IP_DCCP_CCID3 && EXPERIMENTAL
	  ---help---
	    Use higher lower bound for nofeedback timer expiration.

	    The TFRC nofeedback timer normally expires after the maximum of 4
	    RTTs and twice the current send interval (RFC 3448, 4.3). On LANs
	    with a small RTT this can mean a high processing load and reduced
	    performance, since then the nofeedback timer is triggered very
	    frequently.

	    This option enables to set a higher lower bound for the nofeedback
	    value. Values in units of milliseconds can be set here.

	    A value of 0 disables this feature by enforcing the value specified
	    in RFC 3448. The following values have been suggested as bounds for
	    experimental use:
	    	* 16-20ms to match the typical multimedia inter-frame interval
	    	* 100ms as a reasonable compromise [default]
	    	* 1000ms corresponds to the lower TCP RTO bound (RFC 2988, 2.4)

	    The default of 100ms is a compromise between a large value for
	    efficient DCCP implementations, and a small value to avoid disrupting
	    the network in times of congestion.

	    The purpose of the nofeedback timer is to slow DCCP down when there
	    is serious network congestion: experimenting with larger values should
	    therefore not be performed on WANs.


endmenu
endmenu
+65 −54
Original line number Original line Diff line number Diff line
@@ -121,12 +121,15 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx)
/*
/*
 * Update X by
 * Update X by
 *    If (p > 0)
 *    If (p > 0)
 *       x_calc = calcX(s, R, p);
 *       X_calc = calcX(s, R, p);
 *       X = max(min(X_calc, 2 * X_recv), s / t_mbi);
 *       X = max(min(X_calc, 2 * X_recv), s / t_mbi);
 *    Else
 *    Else
 *       If (now - tld >= R)
 *       If (now - tld >= R)
 *          X = max(min(2 * X, 2 * X_recv), s / R);
 *          X = max(min(2 * X, 2 * X_recv), s / R);
 *          tld = now;
 *          tld = now;
 *
 * If X has changed, we also update the scheduled send time t_now,
 * the inter-packet interval t_ipi, and the delta value.
 */ 
 */ 
static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now)
static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now)


@@ -134,8 +137,7 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now)
	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
	const __u32 old_x = hctx->ccid3hctx_x;
	const __u32 old_x = hctx->ccid3hctx_x;


	/* To avoid large error in calcX */
	if (hctx->ccid3hctx_p > 0) {
	if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) {
		hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s,
		hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s,
						     hctx->ccid3hctx_rtt,
						     hctx->ccid3hctx_rtt,
						     hctx->ccid3hctx_p);
						     hctx->ccid3hctx_p);
@@ -223,16 +225,14 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
				       ccid3_tx_state_name(hctx->ccid3hctx_state));
				       ccid3_tx_state_name(hctx->ccid3hctx_state));
			/* Halve sending rate */
			/* Halve sending rate */


			/*  If (X_calc > 2 * X_recv)
			/*  If (p == 0 || X_calc > 2 * X_recv)
			 *    X_recv = max(X_recv / 2, s / (2 * t_mbi));
			 *    X_recv = max(X_recv / 2, s / (2 * t_mbi));
			 *  Else
			 *  Else
			 *    X_recv = X_calc / 4;
			 *    X_recv = X_calc / 4;
			 */
			 */
			BUG_ON(hctx->ccid3hctx_p >= TFRC_SMALLEST_P &&
			BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc);
			       hctx->ccid3hctx_x_calc == 0);


			/* check also if p is zero -> x_calc is infinity? */
			if (hctx->ccid3hctx_p  == 0 ||
			if (hctx->ccid3hctx_p < TFRC_SMALLEST_P ||
			    hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv)
			    hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv)
				hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2,
				hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2,
								    hctx->ccid3hctx_s / (2 * TFRC_T_MBI));
								    hctx->ccid3hctx_s / (2 * TFRC_T_MBI));
@@ -245,9 +245,10 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
		}
		}
		/*
		/*
		 * Schedule no feedback timer to expire in
		 * Schedule no feedback timer to expire in
		 * max(4 * R, 2 * s/X)  =  max(4 * R, 2 * t_ipi)
		 * max(t_RTO, 2 * s/X)  =  max(t_RTO, 2 * t_ipi)
		 * See comments in packet_recv() regarding the value of t_RTO.
		 */
		 */
		t_nfb = max(4 * hctx->ccid3hctx_rtt, 2 * hctx->ccid3hctx_t_ipi);
		t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
		break;
		break;
	case TFRC_SSTATE_NO_SENT:
	case TFRC_SSTATE_NO_SENT:
		DCCP_BUG("Illegal %s state NO_SENT, sk=%p", dccp_role(sk), sk);
		DCCP_BUG("Illegal %s state NO_SENT, sk=%p", dccp_role(sk), sk);
@@ -338,7 +339,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
		 * else
		 * else
		 *       // send the packet in (t_nom - t_now) milliseconds.
		 *       // send the packet in (t_nom - t_now) milliseconds.
		 */
		 */
		if (delay >= hctx->ccid3hctx_delta)
		if (delay - (long)hctx->ccid3hctx_delta >= 0)
			return delay / 1000L;
			return delay / 1000L;
		break;
		break;
	case TFRC_SSTATE_TERM:
	case TFRC_SSTATE_TERM:
@@ -412,10 +413,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
	struct dccp_tx_hist_entry *packet;
	struct dccp_tx_hist_entry *packet;
	struct timeval now;
	struct timeval now;
	unsigned long t_nfb;
	unsigned long t_nfb;
	u32 t_elapsed;
	u32 pinv;
	u32 pinv;
	u32 x_recv;
	long r_sample, t_elapsed;
	u32 r_sample;


	BUG_ON(hctx == NULL);
	BUG_ON(hctx == NULL);


@@ -426,31 +425,44 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)


	opt_recv = &hctx->ccid3hctx_options_received;
	opt_recv = &hctx->ccid3hctx_options_received;


	t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10;
	x_recv = opt_recv->ccid3or_receive_rate;
	pinv = opt_recv->ccid3or_loss_event_rate;

	switch (hctx->ccid3hctx_state) {
	switch (hctx->ccid3hctx_state) {
	case TFRC_SSTATE_NO_FBACK:
	case TFRC_SSTATE_NO_FBACK:
	case TFRC_SSTATE_FBACK:
	case TFRC_SSTATE_FBACK:
		/* Calculate new round trip sample by
		/* get packet from history to look up t_recvdata */
		 * R_sample = (now - t_recvdata) - t_delay */
		/* get t_recvdata from history */
		packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
		packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
						 DCCP_SKB_CB(skb)->dccpd_ack_seq);
						 DCCP_SKB_CB(skb)->dccpd_ack_seq);
		if (unlikely(packet == NULL)) {
		if (unlikely(packet == NULL)) {
			DCCP_WARN("%s, sk=%p, seqno %llu(%s) does't exist "
			DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist "
				  "in history!\n",  dccp_role(sk), sk,
				  "in history!\n",  dccp_role(sk), sk,
			    (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
			    (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
				  dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
				  dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
			return;
			return;
		}
		}


		/* Update RTT */
		/* Update receive rate */
		hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate;

		/* Update loss event rate */
		pinv = opt_recv->ccid3or_loss_event_rate;
		if (pinv == ~0U || pinv == 0)
			hctx->ccid3hctx_p = 0;
		else
 			hctx->ccid3hctx_p = 1000000 / pinv;

		dccp_timestamp(sk, &now);
		dccp_timestamp(sk, &now);

		/*
		 * Calculate new round trip sample as per [RFC 3448, 4.3] by
		 * 	R_sample  =  (now - t_recvdata) - t_elapsed
		 */
		r_sample  = timeval_delta(&now, &packet->dccphtx_tstamp);
		r_sample  = timeval_delta(&now, &packet->dccphtx_tstamp);
		if (unlikely(r_sample <= t_elapsed))
		t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10;
			DCCP_WARN("r_sample=%uus,t_elapsed=%uus\n",

		if (unlikely(r_sample <= 0)) {
			DCCP_WARN("WARNING: R_sample (%ld) <= 0!\n", r_sample);
			r_sample = 0;
		} else if (unlikely(r_sample <= t_elapsed))
			DCCP_WARN("WARNING: r_sample=%ldus <= t_elapsed=%ldus\n",
				  r_sample, t_elapsed);
				  r_sample, t_elapsed);
		else
		else
			r_sample -= t_elapsed;
			r_sample -= t_elapsed;
@@ -473,31 +485,25 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
			hctx->ccid3hctx_t_ld = now;
			hctx->ccid3hctx_t_ld = now;


			ccid3_update_send_time(hctx);
			ccid3_update_send_time(hctx);
			ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
		} else {
			hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 +
					      r_sample / 10;
			ccid3_hc_tx_update_x(sk, &now);
		}


		ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, "
			ccid3_pr_debug("%s(%p), s=%u, w_init=%u, "
			       "r_sample=%us\n", dccp_role(sk), sk,
				       "R_sample=%ldus, X=%u\n", dccp_role(sk),
			       hctx->ccid3hctx_rtt, r_sample);
				       sk, hctx->ccid3hctx_s, w_init, r_sample,
				       hctx->ccid3hctx_x);


		/* Update receive rate */
			ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
		hctx->ccid3hctx_x_recv = x_recv;/* X_recv in bytes per sec */
		} else {
			hctx->ccid3hctx_rtt = (9 * hctx->ccid3hctx_rtt +
					           (u32)r_sample        ) / 10;


		/* Update loss event rate */
			ccid3_hc_tx_update_x(sk, &now);
		if (pinv == ~0 || pinv == 0)
			hctx->ccid3hctx_p = 0;
		else {
			hctx->ccid3hctx_p = 1000000 / pinv;


			if (hctx->ccid3hctx_p < TFRC_SMALLEST_P) {
			ccid3_pr_debug("%s(%p), RTT=%uus (sample=%ldus), s=%u, "
				hctx->ccid3hctx_p = TFRC_SMALLEST_P;
				       "p=%u, X_calc=%u, X=%u\n", dccp_role(sk),
				ccid3_pr_debug("%s, sk=%p, Smallest p used!\n",
				       sk, hctx->ccid3hctx_rtt, r_sample,
					       dccp_role(sk), sk);
				       hctx->ccid3hctx_s, hctx->ccid3hctx_p,
			}
				       hctx->ccid3hctx_x_calc,
				       hctx->ccid3hctx_x);
		}
		}


		/* unschedule no feedback timer */
		/* unschedule no feedback timer */
@@ -512,16 +518,20 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
		 */
		 */
		sk->sk_write_space(sk);
		sk->sk_write_space(sk);


		/* Update timeout interval. We use the alternative variant of
		/*
		 * [RFC 3448, 3.1] which sets the upper bound of t_rto to one
		 * Update timeout interval for the nofeedback timer.
		 * second, as it is suggested for TCP (see RFC 2988, 2.4). */
		 * We use a configuration option to increase the lower bound.
		 * This can help avoid triggering the nofeedback timer too often
		 * ('spinning') on LANs with small RTTs.
		 */
		hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
		hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
					      	   USEC_PER_SEC            );
						   CONFIG_IP_DCCP_CCID3_RTO *
						   (USEC_PER_SEC/1000)	     );
		/*
		/*
		 * Schedule no feedback timer to expire in
		 * Schedule no feedback timer to expire in
		 * max(4 * R, 2 * s/X)  =  max(4 * R, 2 * t_ipi)
		 * max(t_RTO, 2 * s/X)  =  max(t_RTO, 2 * t_ipi)
		 */
		 */
		t_nfb = max(4 * hctx->ccid3hctx_rtt, 2 * hctx->ccid3hctx_t_ipi);
		t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
			
			
		ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to "
		ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to "
			       "expire in %lu jiffies (%luus)\n",
			       "expire in %lu jiffies (%luus)\n",
@@ -535,7 +545,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
		hctx->ccid3hctx_idle = 1;   
		hctx->ccid3hctx_idle = 1;   
		break;
		break;
	case TFRC_SSTATE_NO_SENT:
	case TFRC_SSTATE_NO_SENT:
		DCCP_WARN("Illegal ACK received - no packet has been sent\n");
		if (dccp_sk(sk)->dccps_role == DCCP_ROLE_CLIENT)
			DCCP_WARN("Illegal ACK received - no packet sent\n");
		/* fall through */
		/* fall through */
	case TFRC_SSTATE_TERM:		/* ignore feedback when closing */
	case TFRC_SSTATE_TERM:		/* ignore feedback when closing */
		break;
		break;
+0 −2
Original line number Original line Diff line number Diff line
@@ -51,8 +51,6 @@
/* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */
/* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */
#define TFRC_T_MBI		   64
#define TFRC_T_MBI		   64


#define TFRC_SMALLEST_P		   40

enum ccid3_options {
enum ccid3_options {
	TFRC_OPT_LOSS_EVENT_RATE = 192,
	TFRC_OPT_LOSS_EVENT_RATE = 192,
	TFRC_OPT_LOSS_INTERVALS	 = 193,
	TFRC_OPT_LOSS_INTERVALS	 = 193,
+139 −83
Original line number Original line Diff line number Diff line
@@ -18,10 +18,79 @@
#include "tfrc.h"
#include "tfrc.h"


#define TFRC_CALC_X_ARRSIZE 500
#define TFRC_CALC_X_ARRSIZE 500
#define TFRC_CALC_X_SPLIT   50000	/* 0.05 * 1000000, details below */
#define TFRC_SMALLEST_P	    (TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE)


#define TFRC_CALC_X_SPLIT 50000
/*
/* equivalent to 0.05 */
  TFRC TCP Reno Throughput Equation Lookup Table for f(p)

  The following two-column lookup table implements a part of the TCP throughput
  equation from [RFC 3448, sec. 3.1]:

	 			     s
  X_calc  =  --------------------------------------------------------------
	     R * sqrt(2*b*p/3) + (3 * t_RTO * sqrt(3*b*p/8) * (p + 32*p^3))

  Where:
	X      is the transmit rate in bytes/second
	s      is the packet size in bytes
	R      is the round trip time in seconds
	p      is the loss event rate, between 0 and 1.0, of the number of loss
	              events as a fraction of the number of packets transmitted
	t_RTO  is the TCP retransmission timeout value in seconds
	b      is the number of packets acknowledged by a single TCP ACK

  We can assume that b = 1 and t_RTO is 4 * R. The equation now becomes:

				     s
  X_calc  =  -------------------------------------------------------
	     R * sqrt(p*2/3) + (12 * R * sqrt(p*3/8) * (p + 32*p^3))

  which we can break down into:

                      s
	X_calc  =  ---------
	            R * f(p)

  where f(p) is given for 0 < p <= 1 by:

	f(p)  =  sqrt(2*p/3) + 12 * sqrt(3*p/8) *  (p + 32*p^3)


  Since this is kernel code, floating-point arithmetic is avoided in favour of
  integer arithmetic. This means that nearly all fractional parameters are
  scaled by 1000000:
    * the parameters p and R
    * the return result f(p)
  The lookup table therefore actually tabulates the following function g(q):

  	g(q)  =  1000000 * f(q/1000000)

  Hence, when p <= 1, q must be less than or equal to 1000000. To achieve finer
  granularity for the practically more relevant case of small values of p (up to
  5%), the second column is used; the first one ranges up to 100%.  This split
  corresponds to the value of q = TFRC_CALC_X_SPLIT. At the same time this also
  determines the smallest resolution possible with this lookup table:

    TFRC_SMALLEST_P   =  TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE

  The entire table is generated by:
    for(i=0; i < TFRC_CALC_X_ARRSIZE; i++) {
	lookup[i][0]  =  g((i+1) * 1000000/TFRC_CALC_X_ARRSIZE);
	lookup[i][1]  =  g((i+1) * TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE);
    }

  With the given configuration, we have, with M = TFRC_CALC_X_ARRSIZE-1,
    lookup[0][0]  =  g(1000000/(M+1)) 		 =  1000000 * f(0.2%)
    lookup[M][0]  =  g(1000000)			 =  1000000 * f(100%)
    lookup[0][1]  =  g(TFRC_SMALLEST_P)		  = 1000000 * f(0.01%)
    lookup[M][1]  =  g(TFRC_CALC_X_SPLIT)	 =  1000000 * f(5%)

  In summary, the two columns represent f(p) for the following ranges:
    * The first column is for   0.002  <= p <= 1.0
    * The second column is for  0.0001 <= p <= 0.05
  Where the columns overlap, the second (finer-grained) is given preference,
  i.e. the first column is used only for p >= 0.05.
 */
static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = {
static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = {
	{     37172,   8172 },
	{     37172,   8172 },
	{     53499,  11567 },
	{     53499,  11567 },
@@ -525,52 +594,31 @@ static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = {
	{ 243315981, 271305 }
	{ 243315981, 271305 }
};
};


/* Calculate the send rate as per section 3.1 of RFC3448
/* return largest index i such that fval <= lookup[i][small] */
 
static inline u32 tfrc_binsearch(u32 fval, u8 small)
Returns send rate in bytes per second
{

	u32 try, low = 0, high = TFRC_CALC_X_ARRSIZE - 1;
Integer maths and lookups are used as not allowed floating point in kernel

The function for Xcalc as per section 3.1 of RFC3448 is:

X =                            s
     -------------------------------------------------------------
     R*sqrt(2*b*p/3) + (t_RTO * (3*sqrt(3*b*p/8) * p * (1+32*p^2)))

where 
X is the trasmit rate in bytes/second
s is the packet size in bytes
R is the round trip time in seconds
p is the loss event rate, between 0 and 1.0, of the number of loss events 
  as a fraction of the number of packets transmitted
t_RTO is the TCP retransmission timeout value in seconds
b is the number of packets acknowledged by a single TCP acknowledgement

we can assume that b = 1 and t_RTO is 4 * R. With this the equation becomes:

X =                            s
     -----------------------------------------------------------------------
     R * sqrt(2 * p / 3) + (12 * R * (sqrt(3 * p / 8) * p * (1 + 32 * p^2)))


which we can break down into:

X =     s
     --------
     R * f(p)

where f(p) = sqrt(2 * p / 3) + (12 * sqrt(3 * p / 8) * p * (1 + 32 * p * p))

Function parameters:
s - bytes
R - RTT in usecs
p - loss rate (decimal fraction multiplied by 1,000,000)

Returns Xcalc in bytes per second


DON'T alter this code unless you run test cases against it as the code
	while (low < high) {
has been manipulated to stop underflow/overlow.
		try = (low + high) / 2;
		if (fval <= tfrc_calc_x_lookup[try][small])
			high = try;
		else
			low  = try + 1;
	}
	return high;
}


/**
 * tfrc_calc_x - Calculate the send rate as per section 3.1 of RFC3448
 *
 *  @s: packet size          in bytes
 *  @R: RTT                  scaled by 1000000   (i.e., microseconds)
 *  @p: loss ratio estimate  scaled by 1000000
 *  Returns X_calc           in bytes per second (not scaled).
 *
 * Note: DO NOT alter this code unless you run test cases against it,
 *       as the code has been optimized to stop underflow/overflow.
 */
 */
u32 tfrc_calc_x(u16 s, u32 R, u32 p)
u32 tfrc_calc_x(u16 s, u32 R, u32 p)
{
{
@@ -578,32 +626,37 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
	u32 f;
	u32 f;
	u64 tmp1, tmp2;
	u64 tmp1, tmp2;


	if (p < TFRC_CALC_X_SPLIT)
	/* check against invalid parameters and divide-by-zero   */
		index = (p / (TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE)) - 1;
	BUG_ON(p >  1000000);		/* p must not exceed 100%   */
	else
	BUG_ON(p == 0);			/* f(0) = 0, divide by zero */
		index = (p / (1000000 / TFRC_CALC_X_ARRSIZE)) - 1;
	if (R == 0) {			/* possible  divide by zero */
		DCCP_CRIT("WARNING: RTT is 0, returning maximum X_calc.");
		return ~0U;
 	}


	if (index < 0)
	if (p <= TFRC_CALC_X_SPLIT) 		{     /* 0.0000 < p <= 0.05   */
		/* p should be 0 unless there is a bug in my code */
		if (p < TFRC_SMALLEST_P) {	      /* 0.0000 < p <  0.0001 */
			DCCP_WARN("Value of p (%d) below resolution. "
				  "Substituting %d\n", p, TFRC_SMALLEST_P);
			index = 0;
			index = 0;
		} else 				      /* 0.0001 <= p <= 0.05  */
			index =  p/TFRC_SMALLEST_P - 1;


	if (R == 0) {
 		f = tfrc_calc_x_lookup[index][1];
		DCCP_WARN("RTT==0, setting to 1\n");
		R = 1; /* RTT can't be zero or else divide by zero */
	}


	BUG_ON(index >= TFRC_CALC_X_ARRSIZE);
	} else {	 			      /* 0.05   <  p <= 1.00  */
		index = p/(1000000/TFRC_CALC_X_ARRSIZE) - 1;


	if (p >= TFRC_CALC_X_SPLIT)
		f = tfrc_calc_x_lookup[index][0];
		f = tfrc_calc_x_lookup[index][0];
	else
	}
		f = tfrc_calc_x_lookup[index][1];


	/* The following computes X = s/(R*f(p)) in bytes per second. Since f(p)
	 * and R are both scaled by 1000000, we need to multiply by 1000000^2.
	 * ==> DO NOT alter this unless you test against overflow on 32 bit   */
	tmp1 = ((u64)s * 100000000);
	tmp1 = ((u64)s * 100000000);
	tmp2 = ((u64)R * (u64)f);
	tmp2 = ((u64)R * (u64)f);
	do_div(tmp2, 10000);
	do_div(tmp2, 10000);
	do_div(tmp1, tmp2); 
	do_div(tmp1, tmp2); 
	/* Don't alter above math unless you test due to overflow on 32 bit */


	return (u32)tmp1; 
	return (u32)tmp1; 
}
}
@@ -611,33 +664,36 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
EXPORT_SYMBOL_GPL(tfrc_calc_x);
EXPORT_SYMBOL_GPL(tfrc_calc_x);


/*
/*
 * args: fvalue - function value to match
 *  tfrc_calc_x_reverse_lookup  -  try to find p given f(p)
 * returns: p closest to that value
 *
 *
 * both fvalue and p are multiplied by 1,000,000 to use ints
 *  @fvalue: function value to match, scaled by 1000000
 *  Returns closest match for p, also scaled by 1000000
 */
 */
u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
{
{
	int ctr = 0;
	int index;
	int small;


	if (fvalue < tfrc_calc_x_lookup[0][1])
	if (fvalue == 0)	/* f(p) = 0  whenever  p = 0 */
		return 0;
		return 0;


	if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1])
	/* Error cases. */
		small = 1;
	if (fvalue < tfrc_calc_x_lookup[0][1]) {
	else if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0])
		DCCP_WARN("fvalue %d smaller than resolution\n", fvalue);
		return tfrc_calc_x_lookup[0][1];
	}
	if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) {
		DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue);
		return 1000000;
		return 1000000;
	else
	}
		small = 0;


	while (fvalue > tfrc_calc_x_lookup[ctr][small])
	if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) {
		ctr++;
		index = tfrc_binsearch(fvalue, 1);
		return (index + 1) * TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE;
 	}
 
 
	if (small)
	/* else ... it must be in the coarse-grained column */
		return TFRC_CALC_X_SPLIT * ctr / TFRC_CALC_X_ARRSIZE;
	index = tfrc_binsearch(fvalue, 0);
	else
	return (index + 1) * 1000000 / TFRC_CALC_X_ARRSIZE;
		return 1000000 * ctr / TFRC_CALC_X_ARRSIZE;
}
}


EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup);
EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup);
Loading