linux/net/dccp/ccids/lib/tfrc_equation.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
 *  Copyright (c) 2005 Ian McDonald <[email protected]>
 *  Copyright (c) 2005 Arnaldo Carvalho de Melo <[email protected]>
 *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
 */

#include <linux/module.h>
#include "../../dccp.h"
#include "tfrc.h"

#define TFRC_CALC_X_ARRSIZE
#define TFRC_CALC_X_SPLIT
#define TFRC_SMALLEST_P

/*
  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] =;

/* return largest index i such that fval <= lookup[i][small] */
static inline u32 tfrc_binsearch(u32 fval, u8 small)
{}

/**
 * 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).
 */
u32 tfrc_calc_x(u16 s, u32 R, u32 p)
{}

/**
 *  tfrc_calc_x_reverse_lookup  -  try to find p given f(p)
 *  @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)
{}

/**
 * tfrc_invert_loss_event_rate  -  Compute p so that 10^6 corresponds to 100%
 * @loss_event_rate: loss event rate to invert
 * When @loss_event_rate is large, there is a chance that p is truncated to 0.
 * To avoid re-entering slow-start in that case, we set p = TFRC_SMALLEST_P > 0.
 */
u32 tfrc_invert_loss_event_rate(u32 loss_event_rate)
{}