Add sack tx unit test
[vpp.git] / src / vnet / tcp / tcp_test.c
index 0146154..bca5795 100644 (file)
@@ -35,7 +35,7 @@
 }
 
 static int
-tcp_test_sack ()
+tcp_test_sack_rx ()
 {
   tcp_connection_t _tc, *tc = &_tc;
   sack_scoreboard_t *sb = &tc->sack_sb;
@@ -173,6 +173,145 @@ tcp_test_sack ()
   return 0;
 }
 
+static int
+tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
+{
+  tcp_connection_t _tc, *tc = &_tc;
+  sack_block_t *sacks;
+  int i, verbose = 0;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "verbose"))
+       verbose = 1;
+      else
+       {
+         vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
+                          input);
+         return -1;
+       }
+    }
+
+  memset (tc, 0, sizeof (*tc));
+
+  /*
+   * Add odd sack block pairs
+   */
+  for (i = 1; i < 10; i += 2)
+    {
+      tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
+    }
+
+  TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
+           vec_len (tc->snd_sacks), 5);
+  TCP_TEST ((tc->snd_sacks[0].start = 900),
+           "first sack block start %u expected %u", tc->snd_sacks[0].start,
+           900);
+
+  /*
+   * Try to add one extra
+   */
+  sacks = vec_dup (tc->snd_sacks);
+
+  tcp_update_sack_list (tc, 1100, 1200);
+  TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
+           vec_len (tc->snd_sacks), 5);
+  TCP_TEST ((tc->snd_sacks[0].start == 1100),
+           "first sack block start %u expected %u", tc->snd_sacks[0].start,
+           1100);
+
+  /* restore */
+  vec_free (tc->snd_sacks);
+  tc->snd_sacks = sacks;
+
+  /*
+   * Overlap first 2 segment
+   */
+  tc->rcv_nxt = 300;
+  tcp_update_sack_list (tc, 300, 300);
+  if (verbose)
+    vlib_cli_output (vm, "overlap first 2 segments:\n%U",
+                    format_tcp_sacks, tc->snd_sacks);
+  TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
+           vec_len (tc->snd_sacks), 3);
+  TCP_TEST ((tc->snd_sacks[0].start == 900),
+           "first sack block start %u expected %u", tc->snd_sacks[0].start,
+           500);
+
+  /*
+   * Add a new segment
+   */
+  tcp_update_sack_list (tc, 1100, 1200);
+  if (verbose)
+    vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
+                    format_tcp_sacks, tc->snd_sacks);
+  TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
+           vec_len (tc->snd_sacks), 4);
+  TCP_TEST ((tc->snd_sacks[0].start == 1100),
+           "first sack block start %u expected %u", tc->snd_sacks[0].start,
+           1100);
+
+  /*
+   * Join middle segments
+   */
+  tcp_update_sack_list (tc, 800, 900);
+  if (verbose)
+    vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
+                    format_tcp_sacks, tc->snd_sacks);
+
+  TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
+           vec_len (tc->snd_sacks), 3);
+  TCP_TEST ((tc->snd_sacks[0].start == 700),
+           "first sack block start %u expected %u", tc->snd_sacks[0].start,
+           1100);
+
+  /*
+   * Advance rcv_nxt to overlap all
+   */
+  tc->rcv_nxt = 1200;
+  tcp_update_sack_list (tc, 1200, 1200);
+  if (verbose)
+    vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U",
+                    format_tcp_sacks, tc->snd_sacks);
+  TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
+           vec_len (tc->snd_sacks), 0);
+  return 0;
+}
+
+static int
+tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
+{
+  int res = 0;
+
+  /* Run all tests */
+  if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
+    {
+      if (tcp_test_sack_tx (vm, input))
+       {
+         return -1;
+       }
+
+      if (tcp_test_sack_rx ())
+       {
+         return -1;
+       }
+    }
+  else
+    {
+      if (unformat (input, "tx"))
+       {
+         res = tcp_test_sack_tx (vm, input);
+       }
+      else if (unformat (input, "rx"))
+       {
+         res = tcp_test_sack_rx ();
+       }
+    }
+
+  return res;
+}
+
+
 typedef struct
 {
   u32 offset;
@@ -895,6 +1034,68 @@ tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input)
   return res;
 }
 
+static int
+tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
+{
+  int rv = 0;
+  tcp_connection_t *tc0;
+  u8 sst = SESSION_TYPE_IP4_TCP;
+  ip4_address_t local, remote;
+  u16 local_port, remote_port;
+  tcp_main_t *tm = vnet_get_tcp_main ();
+  int is_add = 1;
+
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "del"))
+       is_add = 0;
+      else if (unformat (input, "add"))
+       is_add = 1;
+      else
+       break;
+    }
+
+  if (is_add)
+    {
+      local.as_u32 = clib_host_to_net_u32 (0x06000101);
+      remote.as_u32 = clib_host_to_net_u32 (0x06000102);
+      local_port = clib_host_to_net_u16 (1234);
+      remote_port = clib_host_to_net_u16 (11234);
+
+      pool_get (tm->connections[0], tc0);
+      memset (tc0, 0, sizeof (*tc0));
+
+      tc0->state = TCP_STATE_ESTABLISHED;
+      tc0->rcv_las = 1;
+      tc0->c_c_index = tc0 - tm->connections[0];
+      tc0->c_lcl_port = local_port;
+      tc0->c_rmt_port = remote_port;
+      tc0->c_is_ip4 = 1;
+      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;
+      tcp_connection_init_vars (tc0);
+
+      TCP_EVT_DBG (TCP_EVT_OPEN, tc0);
+
+      if (stream_session_accept (&tc0->connection, 0 /* listener index */ ,
+                                sst, 0 /* notify */ ))
+       clib_warning ("stream_session_accept failed");
+
+      stream_session_accept_notify (&tc0->connection);
+    }
+  else
+    {
+      tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
+      tc0->state = TCP_STATE_CLOSED;
+      stream_session_disconnect_notify (&tc0->connection);
+    }
+
+  return rv;
+}
+
 static clib_error_t *
 tcp_test (vlib_main_t * vm,
          unformat_input_t * input, vlib_cli_command_t * cmd_arg)
@@ -905,17 +1106,18 @@ tcp_test (vlib_main_t * vm,
     {
       if (unformat (input, "sack"))
        {
-         res = tcp_test_sack ();
+         res = tcp_test_sack (vm, input);
        }
       else if (unformat (input, "fifo"))
        {
          res = tcp_test_fifo (vm, input);
        }
-      else
+      else if (unformat (input, "session"))
        {
-         return clib_error_return (0, "unknown input `%U'",
-                                   format_unformat_error, input);
+         res = tcp_test_session (vm, input);
        }
+      else
+       break;
     }
 
   if (res)