Commit 096cbfb8 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Merge remote-tracking branch 'tor-github/pr/1480'

parents 7824a65a d67db64c
Loading
Loading
Loading
Loading

changes/ticket32196

0 → 100644
+2 −0
Original line number Diff line number Diff line
  o Testing (circuit, EWMA):
    - Add unit tests for circuitmux and EWMA subsystems. Closes ticket 32196.
+2 −54
Original line number Diff line number Diff line
@@ -69,26 +69,20 @@
 *     made to attach all existing circuits to the new policy.
 **/

#define CIRCUITMUX_PRIVATE

#include "core/or/or.h"
#include "core/or/channel.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitmux.h"
#include "core/or/relay.h"

#include "core/or/cell_queue_st.h"
#include "core/or/destroy_cell_queue_st.h"
#include "core/or/or_circuit_st.h"

/*
 * Private typedefs for circuitmux.c
 */

/*
 * Map of muxinfos for circuitmux_t to use; struct is defined below (name
 * of struct must match HT_HEAD line).
 */
typedef struct chanid_circid_muxinfo_map chanid_circid_muxinfo_map_t;

/*
 * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
 * break the hash table code).
@@ -102,49 +96,6 @@ typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t;

typedef struct circuit_muxinfo_s circuit_muxinfo_t;

/*
 * Structures for circuitmux.c
 */

struct circuitmux_s {
  /* Keep count of attached, active circuits */
  unsigned int n_circuits, n_active_circuits;

  /* Total number of queued cells on all circuits */
  unsigned int n_cells;

  /*
   * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
   */
  chanid_circid_muxinfo_map_t *chanid_circid_map;

  /** List of queued destroy cells */
  destroy_cell_queue_t destroy_cell_queue;
  /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
   * returned the destroy queue. Used to force alternation between
   * destroy/non-destroy cells.
   *
   * XXXX There is no reason to think that alternating is a particularly good
   * approach -- it's just designed to prevent destroys from starving other
   * cells completely.
   */
  unsigned int last_cell_was_destroy : 1;
  /** Destroy counter: increment this when a destroy gets queued, decrement
   * when we unqueue it, so we can test to make sure they don't starve.
   */
  int64_t destroy_ctr;

  /*
   * Circuitmux policy; if this is non-NULL, it can override the built-
   * in round-robin active circuits behavior.  This is how EWMA works in
   * the new circuitmux_t world.
   */
  const circuitmux_policy_t *policy;

  /* Policy-specific data */
  circuitmux_policy_data_t *policy_data;
};

/*
 * This struct holds whatever we want to store per attached circuit on a
 * circuitmux_t; right now, just the count of queued cells and the direction.
@@ -221,9 +172,6 @@ chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
            ((unsigned int)(a->chan_id & 0xffffffff)));
}

/* Declare the struct chanid_circid_muxinfo_map type */
HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t);

/* Emit a bunch of hash table stuff */
HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
             chanid_circid_entry_hash, chanid_circid_entries_eq)
+56 −0
Original line number Diff line number Diff line
@@ -158,5 +158,61 @@ void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux,
MOCK_DECL(int, circuitmux_compare_muxes,
          (circuitmux_t *cmux_1, circuitmux_t *cmux_2));

#ifdef CIRCUITMUX_PRIVATE

#include "core/or/destroy_cell_queue_st.h"

/*
 * Map of muxinfos for circuitmux_t to use; struct is defined below (name
 * of struct must match HT_HEAD line).
 */
typedef HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t)
  chanid_circid_muxinfo_map_t;

/*
 * Structures for circuitmux.c
 */

struct circuitmux_s {
  /* Keep count of attached, active circuits */
  unsigned int n_circuits, n_active_circuits;

  /* Total number of queued cells on all circuits */
  unsigned int n_cells;

  /*
   * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
   */
  chanid_circid_muxinfo_map_t *chanid_circid_map;

  /** List of queued destroy cells */
  destroy_cell_queue_t destroy_cell_queue;
  /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
   * returned the destroy queue. Used to force alternation between
   * destroy/non-destroy cells.
   *
   * XXXX There is no reason to think that alternating is a particularly good
   * approach -- it's just designed to prevent destroys from starving other
   * cells completely.
   */
  unsigned int last_cell_was_destroy : 1;
  /** Destroy counter: increment this when a destroy gets queued, decrement
   * when we unqueue it, so we can test to make sure they don't starve.
   */
  int64_t destroy_ctr;

  /*
   * Circuitmux policy; if this is non-NULL, it can override the built-
   * in round-robin active circuits behavior.  This is how EWMA works in
   * the new circuitmux_t world.
   */
  const circuitmux_policy_t *policy;

  /* Policy-specific data */
  circuitmux_policy_data_t *policy_data;
};

#endif /* CIRCUITMUX_PRIVATE */

#endif /* !defined(TOR_CIRCUITMUX_H) */
+0 −109
Original line number Diff line number Diff line
@@ -58,115 +58,6 @@
/** The natural logarithm of 0.5. */
#define LOG_ONEHALF -0.69314718055994529

/*** EWMA structures ***/

typedef struct cell_ewma_s cell_ewma_t;
typedef struct ewma_policy_data_s ewma_policy_data_t;
typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t;

/**
 * The cell_ewma_t structure keeps track of how many cells a circuit has
 * transferred recently.  It keeps an EWMA (exponentially weighted moving
 * average) of the number of cells flushed from the circuit queue onto a
 * connection in channel_flush_from_first_active_circuit().
 */

struct cell_ewma_s {
  /** The last 'tick' at which we recalibrated cell_count.
   *
   * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
   * since the start of this tick have weight greater than 1.0; ones sent
   * earlier have less weight. */
  unsigned int last_adjusted_tick;
  /** The EWMA of the cell count. */
  double cell_count;
  /** True iff this is the cell count for a circuit's previous
   * channel. */
  unsigned int is_for_p_chan : 1;
  /** The position of the circuit within the OR connection's priority
   * queue. */
  int heap_index;
};

struct ewma_policy_data_s {
  circuitmux_policy_data_t base_;

  /**
   * Priority queue of cell_ewma_t for circuits with queued cells waiting
   * for room to free up on the channel that owns this circuitmux.  Kept
   * in heap order according to EWMA.  This was formerly in channel_t, and
   * in or_connection_t before that.
   */
  smartlist_t *active_circuit_pqueue;

  /**
   * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
   * their ewma values rescaled.  This was formerly in channel_t, and in
   * or_connection_t before that.
   */
  unsigned int active_circuit_pqueue_last_recalibrated;
};

struct ewma_policy_circ_data_s {
  circuitmux_policy_circ_data_t base_;

  /**
   * The EWMA count for the number of cells flushed from this circuit
   * onto this circuitmux.  Used to determine which circuit to flush
   * from next.  This was formerly in circuit_t and or_circuit_t.
   */
  cell_ewma_t cell_ewma;

  /**
   * Pointer back to the circuit_t this is for; since we're separating
   * out circuit selection policy like this, we can't attach cell_ewma_t
   * to the circuit_t any more, so we can't use SUBTYPE_P directly to a
   * circuit_t like before; instead get it here.
   */
  circuit_t *circ;
};

#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U

/*** Downcasts for the above types ***/

static ewma_policy_data_t *
TO_EWMA_POL_DATA(circuitmux_policy_data_t *);

static ewma_policy_circ_data_t *
TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *);

/**
 * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
 * if the cast is impossible.
 */

static inline ewma_policy_data_t *
TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
{
  if (!pol) return NULL;
  else {
    tor_assert(pol->magic == EWMA_POL_DATA_MAGIC);
    return DOWNCAST(ewma_policy_data_t, pol);
  }
}

/**
 * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
 * and assert if the cast is impossible.
 */

static inline ewma_policy_circ_data_t *
TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
{
  if (!pol) return NULL;
  else {
    tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC);
    return DOWNCAST(ewma_policy_circ_data_t, pol);
  }
}

/*** Static declarations for circuitmux_ewma.c ***/

static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
+106 −1
Original line number Diff line number Diff line
@@ -22,9 +22,114 @@ void cmux_ewma_set_options(const or_options_t *options,
void circuitmux_ewma_free_all(void);

#ifdef CIRCUITMUX_EWMA_PRIVATE

/*** EWMA structures ***/

typedef struct cell_ewma_s cell_ewma_t;
typedef struct ewma_policy_data_s ewma_policy_data_t;
typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t;

/**
 * The cell_ewma_t structure keeps track of how many cells a circuit has
 * transferred recently.  It keeps an EWMA (exponentially weighted moving
 * average) of the number of cells flushed from the circuit queue onto a
 * connection in channel_flush_from_first_active_circuit().
 */

struct cell_ewma_s {
  /** The last 'tick' at which we recalibrated cell_count.
   *
   * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
   * since the start of this tick have weight greater than 1.0; ones sent
   * earlier have less weight. */
  unsigned int last_adjusted_tick;
  /** The EWMA of the cell count. */
  double cell_count;
  /** True iff this is the cell count for a circuit's previous
   * channel. */
  unsigned int is_for_p_chan : 1;
  /** The position of the circuit within the OR connection's priority
   * queue. */
  int heap_index;
};

struct ewma_policy_data_s {
  circuitmux_policy_data_t base_;

  /**
   * Priority queue of cell_ewma_t for circuits with queued cells waiting
   * for room to free up on the channel that owns this circuitmux.  Kept
   * in heap order according to EWMA.  This was formerly in channel_t, and
   * in or_connection_t before that.
   */
  smartlist_t *active_circuit_pqueue;

  /**
   * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
   * their ewma values rescaled.  This was formerly in channel_t, and in
   * or_connection_t before that.
   */
  unsigned int active_circuit_pqueue_last_recalibrated;
};

struct ewma_policy_circ_data_s {
  circuitmux_policy_circ_data_t base_;

  /**
   * The EWMA count for the number of cells flushed from this circuit
   * onto this circuitmux.  Used to determine which circuit to flush
   * from next.  This was formerly in circuit_t and or_circuit_t.
   */
  cell_ewma_t cell_ewma;

  /**
   * Pointer back to the circuit_t this is for; since we're separating
   * out circuit selection policy like this, we can't attach cell_ewma_t
   * to the circuit_t any more, so we can't use SUBTYPE_P directly to a
   * circuit_t like before; instead get it here.
   */
  circuit_t *circ;
};

#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U

/*** Downcasts for the above types ***/

/**
 * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
 * if the cast is impossible.
 */

static inline ewma_policy_data_t *
TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
{
  if (!pol) return NULL;
  else {
    tor_assert(pol->magic == EWMA_POL_DATA_MAGIC);
    return DOWNCAST(ewma_policy_data_t, pol);
  }
}

/**
 * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
 * and assert if the cast is impossible.
 */

static inline ewma_policy_circ_data_t *
TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
{
  if (!pol) return NULL;
  else {
    tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC);
    return DOWNCAST(ewma_policy_circ_data_t, pol);
  }
}

STATIC unsigned cell_ewma_get_current_tick_and_fraction(double *remainder_out);
STATIC void cell_ewma_initialize_ticks(void);
#endif

#endif /* CIRCUITMUX_EWMA_PRIVATE */

#endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */
Loading