-/**
- * \brief Configure an ipv6 source address range
- * @param vm vlib_main_t pointer
- * @param start first ipv6 address in the source address range
- * @param end last ipv6 address in the source address range
- * @param table_id VRF / table ID, 0 for the default FIB
- * @return 0 if all OK, else an error indication from api_errno.h
- */
-
-int
-tcp_configure_v6_source_address_range (vlib_main_t * vm,
- ip6_address_t * start,
- ip6_address_t * end, u32 table_id)
-{
- tcp_main_t *tm = vnet_get_tcp_main ();
- fib_prefix_t prefix;
- u32 fib_index = 0;
- fib_node_index_t fei;
- u32 sw_if_index;
-
- clib_memset (&prefix, 0, sizeof (prefix));
-
- fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
-
- if (fib_index == ~0)
- return VNET_API_ERROR_NO_SUCH_FIB;
-
- while (1)
- {
- int i;
- ip6_address_t tmp;
- dpo_id_t dpo = DPO_INVALID;
-
- /* Remember this address */
- vec_add1 (tm->ip6_src_addresses, start[0]);
-
- /* Lookup the prefix, to identify the interface involved */
- prefix.fp_len = 128;
- prefix.fp_proto = FIB_PROTOCOL_IP6;
- memcpy (&prefix.fp_addr.ip6, start, sizeof (ip6_address_t));
-
- fei = fib_table_lookup (fib_index, &prefix);
-
- /* Couldn't find route to destination. Bail out. */
- if (fei == FIB_NODE_INDEX_INVALID)
- return VNET_API_ERROR_NEXT_HOP_NOT_IN_FIB;
-
- sw_if_index = fib_entry_get_resolving_interface (fei);
-
- if (sw_if_index == (u32) ~ 0)
- return VNET_API_ERROR_NO_MATCHING_INTERFACE;
-
- /* Add a proxy neighbor discovery entry for this address */
- ip6_neighbor_proxy_add_del (sw_if_index, start, 0 /* is_del */ );
-
- /* Add a receive adjacency for this address */
- receive_dpo_add_or_lock (DPO_PROTO_IP6, ~0 /* sw_if_index */ ,
- NULL, &dpo);
-
- fib_table_entry_special_dpo_update (fib_index,
- &prefix,
- FIB_SOURCE_API,
- FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
- dpo_reset (&dpo);
-
- /* Done with the entire range? */
- if (!memcmp (start, end, sizeof (start[0])))
- break;
-
- /* Increment the address. DGMS. */
- tmp = start[0];
- for (i = 15; i >= 0; i--)
- {
- tmp.as_u8[i] += 1;
- if (tmp.as_u8[i] != 0)
- break;
- }
- start[0] = tmp;
- }
- return 0;
-}
-
-static clib_error_t *
-tcp_src_address (vlib_main_t * vm,
- unformat_input_t * input, vlib_cli_command_t * cmd_arg)
-{
- ip4_address_t v4start, v4end;
- ip6_address_t v6start, v6end;
- u32 table_id = 0;
- int v4set = 0;
- int v6set = 0;
- int rv;
-
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (input, "%U - %U", unformat_ip4_address, &v4start,
- unformat_ip4_address, &v4end))
- v4set = 1;
- else if (unformat (input, "%U", unformat_ip4_address, &v4start))
- {
- memcpy (&v4end, &v4start, sizeof (v4start));
- v4set = 1;
- }
- else if (unformat (input, "%U - %U", unformat_ip6_address, &v6start,
- unformat_ip6_address, &v6end))
- v6set = 1;
- else if (unformat (input, "%U", unformat_ip6_address, &v6start))
- {
- memcpy (&v6end, &v6start, sizeof (v6start));
- v6set = 1;
- }
- else if (unformat (input, "fib-table %d", &table_id))
- ;
- else
- break;
- }
-
- if (!v4set && !v6set)
- return clib_error_return (0, "at least one v4 or v6 address required");
-
- if (v4set)
- {
- rv = tcp_configure_v4_source_address_range (vm, &v4start, &v4end,
- table_id);
- switch (rv)
- {
- case 0:
- break;
-
- case VNET_API_ERROR_NO_SUCH_FIB:
- return clib_error_return (0, "Invalid table-id %d", table_id);
-
- case VNET_API_ERROR_INVALID_ARGUMENT:
- return clib_error_return (0, "Invalid address range %U - %U",
- format_ip4_address, &v4start,
- format_ip4_address, &v4end);
- default:
- return clib_error_return (0, "error %d", rv);
- break;
- }
- }
- if (v6set)
- {
- rv = tcp_configure_v6_source_address_range (vm, &v6start, &v6end,
- table_id);
- switch (rv)
- {
- case 0:
- break;
-
- case VNET_API_ERROR_NO_SUCH_FIB:
- return clib_error_return (0, "Invalid table-id %d", table_id);
-
- default:
- return clib_error_return (0, "error %d", rv);
- break;
- }
- }
- return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (tcp_src_address_command, static) =
-{
- .path = "tcp src-address",
- .short_help = "tcp src-address <ip-addr> [- <ip-addr>] add src address range",
- .function = tcp_src_address,
-};
-/* *INDENT-ON* */
-
-static u8 *
-tcp_scoreboard_dump_trace (u8 * s, sack_scoreboard_t * sb)
-{
-#if TCP_SCOREBOARD_TRACE
-
- scoreboard_trace_elt_t *block;
- int i = 0;
-
- if (!sb->trace)
- return s;
-
- s = format (s, "scoreboard trace:");
- vec_foreach (block, sb->trace)
- {
- s = format (s, "{%u, %u, %u, %u, %u}, ", block->start, block->end,
- block->ack, block->snd_una_max, block->group);
- if ((++i % 3) == 0)
- s = format (s, "\n");
- }
- return s;
-#else
- return 0;
-#endif
-}
-
-static clib_error_t *
-tcp_show_scoreboard_trace_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd_arg)
-{
- transport_connection_t *tconn = 0;
- tcp_connection_t *tc;
- u8 *s = 0;
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (input, "%U", unformat_transport_connection, &tconn,
- TRANSPORT_PROTO_TCP))
- ;
- else
- return clib_error_return (0, "unknown input `%U'",
- format_unformat_error, input);
- }
-
- if (!TCP_SCOREBOARD_TRACE)
- {
- vlib_cli_output (vm, "scoreboard tracing not enabled");
- return 0;
- }
-
- tc = tcp_get_connection_from_transport (tconn);
- s = tcp_scoreboard_dump_trace (s, &tc->sack_sb);
- vlib_cli_output (vm, "%v", s);
- return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (tcp_show_scoreboard_trace_command, static) =
-{
- .path = "show tcp scoreboard trace",
- .short_help = "show tcp scoreboard trace <connection>",
- .function = tcp_show_scoreboard_trace_fn,
-};
-/* *INDENT-ON* */
-
-u8 *
-tcp_scoreboard_replay (u8 * s, tcp_connection_t * tc, u8 verbose)
-{
- int i, trace_len;
- scoreboard_trace_elt_t *trace;
- u32 next_ack, left, group, has_new_ack = 0;
- tcp_connection_t _dummy_tc, *dummy_tc = &_dummy_tc;
- sack_block_t *block;
-
- if (!TCP_SCOREBOARD_TRACE)
- {
- s = format (s, "scoreboard tracing not enabled");
- return s;
- }
-
- if (!tc)
- return s;
-
- clib_memset (dummy_tc, 0, sizeof (*dummy_tc));
- tcp_connection_timers_init (dummy_tc);
- scoreboard_init (&dummy_tc->sack_sb);
- dummy_tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
-
-#if TCP_SCOREBOARD_TRACE
- trace = tc->sack_sb.trace;
- trace_len = vec_len (tc->sack_sb.trace);
-#endif
-
- for (i = 0; i < trace_len; i++)
- {
- if (trace[i].ack != 0)
- {
- dummy_tc->snd_una = trace[i].ack - 1448;
- dummy_tc->snd_una_max = trace[i].ack;
- }
- }
-
- left = 0;
- while (left < trace_len)
- {
- group = trace[left].group;
- vec_reset_length (dummy_tc->rcv_opts.sacks);
- has_new_ack = 0;
- while (trace[left].group == group)
- {
- if (trace[left].ack != 0)
- {
- if (verbose)
- s = format (s, "Adding ack %u, snd_una_max %u, segs: ",
- trace[left].ack, trace[left].snd_una_max);
- dummy_tc->snd_una_max = trace[left].snd_una_max;
- next_ack = trace[left].ack;
- has_new_ack = 1;
- }
- else
- {
- if (verbose)
- s = format (s, "[%u, %u], ", trace[left].start,
- trace[left].end);
- vec_add2 (dummy_tc->rcv_opts.sacks, block, 1);
- block->start = trace[left].start;
- block->end = trace[left].end;
- }
- left++;
- }
-
- /* Push segments */
- tcp_rcv_sacks (dummy_tc, next_ack);
- if (has_new_ack)
- dummy_tc->snd_una = next_ack + dummy_tc->sack_sb.snd_una_adv;
-
- if (verbose)
- s = format (s, "result: %U", format_tcp_scoreboard,
- &dummy_tc->sack_sb);
-
- }
- s = format (s, "result: %U", format_tcp_scoreboard, &dummy_tc->sack_sb);
-
- return s;
-}
-
-static clib_error_t *
-tcp_scoreboard_trace_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd_arg)
-{
- transport_connection_t *tconn = 0;
- tcp_connection_t *tc = 0;
- u8 *str = 0;
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (input, "%U", unformat_transport_connection, &tconn,
- TRANSPORT_PROTO_TCP))
- ;
- else
- return clib_error_return (0, "unknown input `%U'",
- format_unformat_error, input);
- }
-
- if (!TCP_SCOREBOARD_TRACE)
- {
- vlib_cli_output (vm, "scoreboard tracing not enabled");
- return 0;
- }
-
- tc = tcp_get_connection_from_transport (tconn);
- if (!tc)
- {
- vlib_cli_output (vm, "connection not found");
- return 0;
- }
- str = tcp_scoreboard_replay (str, tc, 1);
- vlib_cli_output (vm, "%v", str);
- return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (tcp_replay_scoreboard_command, static) =
-{
- .path = "tcp replay scoreboard",
- .short_help = "tcp replay scoreboard <connection>",
- .function = tcp_scoreboard_trace_fn,
-};
-/* *INDENT-ON* */
-
-static clib_error_t *
-show_tcp_punt_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd_arg)
-{
- tcp_main_t *tm = vnet_get_tcp_main ();
- if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
- return clib_error_return (0, "unknown input `%U'", format_unformat_error,
- input);
- vlib_cli_output (vm, "IPv4 TCP punt: %s",
- tm->punt_unknown4 ? "enabled" : "disabled");
- vlib_cli_output (vm, "IPv6 TCP punt: %s",
- tm->punt_unknown6 ? "enabled" : "disabled");
- return 0;
-}
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (show_tcp_punt_command, static) =
-{
- .path = "show tcp punt",
- .short_help = "show tcp punt",
- .function = show_tcp_punt_fn,
-};
-/* *INDENT-ON* */