aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/tcp/tcp_test.c
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2017-05-24 18:03:56 -0700
committerDave Barach <openvpp@barachs.net>2017-06-09 16:47:19 +0000
commit93992a9048cb6e5dcd22de5091e72de778122627 (patch)
treef295bb870ad1614d9327828dd036fb03f60e455e /src/vnet/tcp/tcp_test.c
parent583dc8d3e23a780c85ebe48ea59f0338aad4df17 (diff)
Implement sack based tcp loss recovery (RFC 6675)
- refactor existing congestion control code (RFC 6582/5681). Handling of ack feedback now consists of: ack parsing, cc event detection, event handling, congestion control update - extend sack scoreboard to support sack based retransmissions - basic implementation of Eifel detection algorithm (RFC 3522) for detecting spurious retransmissions - actually initialize the per-thread frame freelist hash tables - increase worker stack size to 2mb - fix session queue node out-of-buffer handling - ensure that the local buffer cache vec_len matches reality - avoid 2x spurious event requeues when short of buffers - count out-of-buffer events - make the builtin server thread-safe - fix bihash template threading issue: need to paint -1 across uninitialized working_copy_length vector elements (via rebase from master) Change-Id: I646cb9f1add9a67d08f4a87badbcb117980ebfc4 Signed-off-by: Florin Coras <fcoras@cisco.com> Signed-off-by: Dave Barach <dbarach@cisco.com>
Diffstat (limited to 'src/vnet/tcp/tcp_test.c')
-rw-r--r--src/vnet/tcp/tcp_test.c53
1 files changed, 32 insertions, 21 deletions
diff --git a/src/vnet/tcp/tcp_test.c b/src/vnet/tcp/tcp_test.c
index 2af3848436f..3f8afa40e54 100644
--- a/src/vnet/tcp/tcp_test.c
+++ b/src/vnet/tcp/tcp_test.c
@@ -54,7 +54,7 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
tc->snd_una = 0;
tc->snd_una_max = 1000;
tc->snd_nxt = 1000;
- tc->opt.flags |= TCP_OPTS_FLAG_SACK;
+ tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
scoreboard_init (&tc->sack_sb);
for (i = 0; i < 1000 / 100; i++)
@@ -70,9 +70,9 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
for (i = 0; i < 1000 / 200; i++)
{
- vec_add1 (tc->opt.sacks, sacks[i * 2]);
+ vec_add1 (tc->rcv_opts.sacks, sacks[i * 2]);
}
- tc->opt.n_sack_blocks = vec_len (tc->opt.sacks);
+ tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
tcp_rcv_sacks (tc, 0);
if (verbose)
@@ -93,18 +93,17 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
TCP_TEST ((sb->last_sacked_bytes == 400),
"last sacked bytes %d", sb->last_sacked_bytes);
- TCP_TEST ((sb->max_byte_sacked == 900),
- "max byte sacked %u", sb->max_byte_sacked);
+ TCP_TEST ((sb->high_sacked == 900), "max byte sacked %u", sb->high_sacked);
/*
* Inject odd blocks
*/
- vec_reset_length (tc->opt.sacks);
+ vec_reset_length (tc->rcv_opts.sacks);
for (i = 0; i < 1000 / 200; i++)
{
- vec_add1 (tc->opt.sacks, sacks[i * 2 + 1]);
+ vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
}
- tc->opt.n_sack_blocks = vec_len (tc->opt.sacks);
+ tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
tcp_rcv_sacks (tc, 0);
if (verbose)
@@ -118,8 +117,7 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
"first hole start %u end %u", hole->start, hole->end);
TCP_TEST ((sb->sacked_bytes == 900), "sacked bytes %d", sb->sacked_bytes);
TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
- TCP_TEST ((sb->max_byte_sacked == 1000),
- "max sacked byte %u", sb->max_byte_sacked);
+ TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
TCP_TEST ((sb->last_sacked_bytes == 500),
"last sacked bytes %d", sb->last_sacked_bytes);
@@ -135,8 +133,7 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
"scoreboard has %d elements", pool_elts (sb->holes));
TCP_TEST ((sb->snd_una_adv == 900),
"snd_una_adv after ack %u", sb->snd_una_adv);
- TCP_TEST ((sb->max_byte_sacked == 1000),
- "max sacked byte %u", sb->max_byte_sacked);
+ TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
TCP_TEST ((sb->last_sacked_bytes == 0),
"last sacked bytes %d", sb->last_sacked_bytes);
@@ -145,11 +142,11 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
* Add new block
*/
- vec_reset_length (tc->opt.sacks);
+ vec_reset_length (tc->rcv_opts.sacks);
block.start = 1200;
block.end = 1300;
- vec_add1 (tc->opt.sacks, block);
+ vec_add1 (tc->rcv_opts.sacks, block);
if (verbose)
vlib_cli_output (vm, "add [1200, 1300]:\n%U", format_tcp_scoreboard, sb);
@@ -171,8 +168,7 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
"first hole start %u end %u", hole->start, hole->end);
TCP_TEST ((sb->snd_una_adv == 0),
"snd_una_adv after ack %u", sb->snd_una_adv);
- TCP_TEST ((sb->max_byte_sacked == 1300),
- "max sacked byte %u", sb->max_byte_sacked);
+ TCP_TEST ((sb->high_sacked == 1300), "max sacked byte %u", sb->high_sacked);
hole = scoreboard_last_hole (sb);
TCP_TEST ((hole->start == 1300 && hole->end == 1500),
"last hole start %u end %u", hole->start, hole->end);
@@ -182,7 +178,7 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
* Ack first hole
*/
- vec_reset_length (tc->opt.sacks);
+ vec_reset_length (tc->rcv_opts.sacks);
tcp_rcv_sacks (tc, 1200);
if (verbose)
@@ -196,8 +192,16 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
"scoreboard has %d elements", pool_elts (sb->holes));
/*
- * Remove all
+ * Add some more blocks and then remove all
*/
+ vec_reset_length (tc->rcv_opts.sacks);
+ for (i = 0; i < 5; i++)
+ {
+ block.start = i * 100 + 1200;
+ block.end = (i + 1) * 100 + 1200;
+ vec_add1 (tc->rcv_opts.sacks, block);
+ }
+ tcp_rcv_sacks (tc, 1900);
scoreboard_clear (sb);
if (verbose)
@@ -205,6 +209,9 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
TCP_TEST ((pool_elts (sb->holes) == 0),
"number of holes %d", pool_elts (sb->holes));
+ TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
+ TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
+
/*
* Re-inject odd blocks and ack them all
*/
@@ -214,9 +221,9 @@ tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
tc->snd_nxt = 1000;
for (i = 0; i < 5; i++)
{
- vec_add1 (tc->opt.sacks, sacks[i * 2 + 1]);
+ vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
}
- tc->opt.n_sack_blocks = vec_len (tc->opt.sacks);
+ tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
tcp_rcv_sacks (tc, 0);
if (verbose)
vlib_cli_output (vm, "sb added odd blocks and ack [0, 950]:\n%U",
@@ -740,6 +747,10 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
}
+ /* Try to peek beyond the data */
+ rv = svm_fifo_peek (f, svm_fifo_max_dequeue (f), vec_len (data), data_buf);
+ TCP_TEST ((rv == 0), "peeked %u expected 0", rv);
+
vec_free (data_buf);
svm_fifo_free (f);
vec_free (test_data);
@@ -1239,7 +1250,7 @@ tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
tc0->c_thread_index = 0;
tc0->c_lcl_ip4.as_u32 = local.as_u32;
tc0->c_rmt_ip4.as_u32 = remote.as_u32;
- tc0->opt.mss = 1450;
+ tc0->rcv_opts.mss = 1450;
tcp_connection_init_vars (tc0);
TCP_EVT_DBG (TCP_EVT_OPEN, tc0);
{ color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (c) 2015 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * ip/ip_lookup.c: ip4/6 adjacency and lookup table management
 *
 * Copyright (c) 2008 Eliot Dresselhaus
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <vnet/ip/ip_container_proxy.h>
#include <vnet/ip/format.h>
#include <vnet/fib/fib_table.h>
#include <vnet/dpo/l3_proxy_dpo.h>
#include <vnet/dpo/load_balance.h>

clib_error_t *
vnet_ip_container_proxy_add_del (vnet_ip_container_proxy_args_t * args)
{
  u32 fib_index;

  if (!vnet_sw_interface_is_api_valid (vnet_get_main (), args->sw_if_index))
    return clib_error_return_code (0, VNET_API_ERROR_INVALID_INTERFACE, 0,
				   "invalid sw_if_index");

  fib_index = fib_table_get_table_id_for_sw_if_index (args->prefix.fp_proto,
						      args->sw_if_index);
  if (args->is_add)
    {
      dpo_id_t proxy_dpo = DPO_INVALID;
      l3_proxy_dpo_add_or_lock (fib_proto_to_dpo (args->prefix.fp_proto),
				args->sw_if_index, &proxy_dpo);
      fib_table_entry_special_dpo_add (fib_index,
				       &args->prefix,
				       FIB_SOURCE_PROXY,
				       FIB_ENTRY_FLAG_EXCLUSIVE, &proxy_dpo);
      dpo_reset (&proxy_dpo);
    }
  else
    {
      fib_table_entry_special_remove (fib_index, &args->prefix,
				      FIB_SOURCE_PROXY);
    }
  return 0;
}

u8
ip_container_proxy_is_set (fib_prefix_t * pfx, u32 sw_if_index)
{
  u32 fib_index;
  fib_node_index_t fei;
  const dpo_id_t *dpo;
  l3_proxy_dpo_t *l3p;
  load_balance_t *lb0;

  fib_index = fib_table_get_table_id_for_sw_if_index (pfx->fp_proto,
						      sw_if_index);
  if (fib_index == ~0)
    return 0;

  fei = fib_table_lookup_exact_match (fib_index, pfx);
  if (fei == FIB_NODE_INDEX_INVALID)
    return 0;

  dpo = fib_entry_contribute_ip_forwarding (fei);
  lb0 = load_balance_get (dpo->dpoi_index);
  dpo = load_balance_get_bucket_i (lb0, 0);
  if (dpo->dpoi_type != DPO_L3_PROXY)
    return 0;

  l3p = l3_proxy_dpo_get (dpo->dpoi_index);
  return (l3p->l3p_sw_if_index == sw_if_index);
}

typedef struct ip_container_proxy_walk_ctx_t_
{
  ip_container_proxy_cb_t cb;
  void *ctx;
} ip_container_proxy_walk_ctx_t;

static fib_table_walk_rc_t
ip_container_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
{
  ip_container_proxy_walk_ctx_t *ctx = arg;
  const fib_prefix_t *pfx;
  const dpo_id_t *dpo;
  load_balance_t *lb;
  l3_proxy_dpo_t *l3p;

  pfx = fib_entry_get_prefix (fei);
  if (fib_entry_is_sourced (fei, FIB_SOURCE_PROXY))
    {
      dpo = fib_entry_contribute_ip_forwarding (fei);
      lb = load_balance_get (dpo->dpoi_index);
      dpo = load_balance_get_bucket_i (lb, 0);
      l3p = l3_proxy_dpo_get (dpo->dpoi_index);
      ctx->cb (pfx, l3p->l3p_sw_if_index, ctx->ctx);
    }

  return FIB_TABLE_WALK_CONTINUE;
}

void
ip_container_proxy_walk (ip_container_proxy_cb_t cb, void *ctx)
{
  fib_table_t *fib_table;
  ip_container_proxy_walk_ctx_t wctx = {
    .cb = cb,
    .ctx = ctx,
  };

  /* *INDENT-OFF* */
  pool_foreach (fib_table, ip4_main.fibs)
   {
    fib_table_walk(fib_table->ft_index,
                   FIB_PROTOCOL_IP4,
                   ip_container_proxy_fib_table_walk,
                   &wctx);
  }
  pool_foreach (fib_table, ip6_main.fibs)
   {
    fib_table_walk(fib_table->ft_index,
                   FIB_PROTOCOL_IP6,
                   ip_container_proxy_fib_table_walk,
                   &wctx);
  }
  /* *INDENT-ON* */
}

clib_error_t *
ip_container_cmd (vlib_main_t * vm,
		  unformat_input_t * main_input, vlib_cli_command_t * cmd)
{
  unformat_input_t _line_input, *line_input = &_line_input;
  fib_prefix_t pfx;
  u32 is_del, addr_set = 0;
  vnet_main_t *vnm;
  u32 sw_if_index;

  vnm = vnet_get_main ();
  is_del = 0;
  sw_if_index = ~0;
  clib_memset (&pfx, 0, sizeof (pfx));

  /* Get a line of input. */
  if (!unformat_user (main_input, unformat_line_input, line_input))
    return 0;

  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
	{
	  pfx.fp_proto = FIB_PROTOCOL_IP4;
	  pfx.fp_len = 32;
	  addr_set = 1;
	}
      else if (unformat (line_input, "%U",
			 unformat_ip6_address, &pfx.fp_addr.ip6))
	{
	  pfx.fp_proto = FIB_PROTOCOL_IP6;
	  pfx.fp_len = 128;
	  addr_set = 1;
	}
      else if (unformat (line_input, "%U",
			 unformat_vnet_sw_interface, vnm, &sw_if_index))
	;
      else if (unformat (line_input, "del"))
	is_del = 1;
      else
	{
	  unformat_free (line_input);
	  return (clib_error_return (0, "unknown input '%U'",
				     format_unformat_error, line_input));
	}
    }

  if (~0 == sw_if_index || !addr_set)
    {
      unformat_free (line_input);
      vlib_cli_output (vm, "interface and address must be set");
      return 0;
    }

  vnet_ip_container_proxy_args_t args = {
    .prefix = pfx,
    .sw_if_index = sw_if_index,
    .is_add = !is_del,
  };
  vnet_ip_container_proxy_add_del (&args);
  unformat_free (line_input);
  return (NULL);
}

/* *INDENT-OFF* */
VLIB_CLI_COMMAND (ip_container_command_node, static) = {
  .path = "ip container",
  .function = ip_container_cmd,
  .short_help = "ip container <address> <interface>",
  .is_mp_safe = 1,
};
/* *INDENT-ON* */

clib_error_t *
show_ip_container_cmd_fn (vlib_main_t * vm, unformat_input_t * main_input,
			  vlib_cli_command_t * cmd)
{
  unformat_input_t _line_input, *line_input = &_line_input;
  vnet_main_t *vnm = vnet_get_main ();
  fib_prefix_t pfx;
  u32 sw_if_index = ~0;
  u8 has_proxy;

  if (!unformat_user (main_input, unformat_line_input, line_input))
    return 0;
  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
	{
	  pfx.fp_proto = FIB_PROTOCOL_IP4;
	  pfx.fp_len = 32;
	}
      else if (unformat (line_input, "%U",
			 unformat_ip6_address, &pfx.fp_addr.ip6))
	{
	  pfx.fp_proto = FIB_PROTOCOL_IP6;
	  pfx.fp_len = 128;
	}
      else if (unformat (line_input, "%U",
			 unformat_vnet_sw_interface, vnm, &sw_if_index))
	;
      else
	{
	  unformat_free (line_input);
	  return (clib_error_return (0, "unknown input '%U'",
				     format_unformat_error, line_input));
	}
    }

  if (~0 == sw_if_index)
    {
      unformat_free (line_input);
      vlib_cli_output (vm, "no interface");
      return (clib_error_return (0, "no interface"));
    }

  has_proxy = ip_container_proxy_is_set (&pfx, sw_if_index);
  vlib_cli_output (vm, "ip container proxy is: %s", has_proxy ? "on" : "off");

  unformat_free (line_input);
  return 0;
}

/* *INDENT-OFF* */
VLIB_CLI_COMMAND (show_ip_container_command, static) = {
  .path = "show ip container",
  .function = show_ip_container_cmd_fn,
  .short_help = "show ip container <address> <interface>",
  .is_mp_safe = 1,
};
/* *INDENT-ON* */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */