TCP source address automation

- v6 support
- Non-default VRF ID collection
- Break up ip source address list into CLI + API-friendly functions
- Automate proxy arp / proxy nd configuration
- Automate local adjacency insertion
- Binary API support

Change-Id: Iede31184f65cc1ec8c414447d2d60a1334e3fe15
Signed-off-by: Dave Barach <dave@barachs.net>
This commit is contained in:
Dave Barach
2017-08-15 19:03:44 -04:00
committed by Florin Coras
parent f413bef135
commit 3bbcfab119
8 changed files with 486 additions and 17 deletions
+73 -3
View File
@@ -4733,7 +4733,8 @@ _(sw_interface_set_mtu_reply) \
_(p2p_ethernet_add_reply) \
_(p2p_ethernet_del_reply) \
_(lldp_config_reply) \
_(sw_interface_set_lldp_reply)
_(sw_interface_set_lldp_reply) \
_(tcp_configure_src_addresses_reply)
#define _(n) \
static void vl_api_##n##_t_handler \
@@ -5027,7 +5028,8 @@ _(SW_INTERFACE_GET_TABLE_REPLY, sw_interface_get_table_reply) \
_(P2P_ETHERNET_ADD_REPLY, p2p_ethernet_add_reply) \
_(P2P_ETHERNET_DEL_REPLY, p2p_ethernet_del_reply) \
_(LLDP_CONFIG_REPLY, lldp_config_reply) \
_(SW_INTERFACE_SET_LLDP_REPLY, sw_interface_set_lldp_reply)
_(SW_INTERFACE_SET_LLDP_REPLY, sw_interface_set_lldp_reply) \
_(TCP_CONFIGURE_SRC_ADDRESSES_REPLY, tcp_configure_src_addresses_reply)
#define foreach_standalone_reply_msg \
_(SW_INTERFACE_EVENT, sw_interface_event) \
@@ -19694,6 +19696,73 @@ api_sw_interface_set_lldp (vat_main_t * vam)
return ret;
}
static int
api_tcp_configure_src_addresses (vat_main_t * vam)
{
vl_api_tcp_configure_src_addresses_t *mp;
unformat_input_t *i = vam->input;
ip4_address_t v4first, v4last;
ip6_address_t v6first, v6last;
u8 range_set = 0;
u32 vrf_id = 0;
int ret;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U - %U",
unformat_ip4_address, &v4first,
unformat_ip4_address, &v4last))
{
if (range_set)
{
errmsg ("one range per message (range already set)");
return -99;
}
range_set = 1;
}
else if (unformat (i, "%U - %U",
unformat_ip6_address, &v6first,
unformat_ip6_address, &v6last))
{
if (range_set)
{
errmsg ("one range per message (range already set)");
return -99;
}
range_set = 2;
}
else if (unformat (i, "vrf %d", &vrf_id))
;
else
break;
}
if (range_set == 0)
{
errmsg ("address range not set");
return -99;
}
M (TCP_CONFIGURE_SRC_ADDRESSES, mp);
mp->vrf_id = ntohl (vrf_id);
/* ipv6? */
if (range_set == 2)
{
mp->is_ipv6 = 1;
clib_memcpy (mp->first_address, &v6first, sizeof (v6first));
clib_memcpy (mp->last_address, &v6last, sizeof (v6last));
}
else
{
mp->is_ipv6 = 0;
clib_memcpy (mp->first_address, &v4first, sizeof (v4first));
clib_memcpy (mp->last_address, &v4last, sizeof (v4last));
}
S (mp);
W (ret);
return ret;
}
static int
q_or_quit (vat_main_t * vam)
{
@@ -20467,7 +20536,8 @@ _(sw_interface_get_table, "<intfc> | sw_if_index <id> [ipv6]") \
_(p2p_ethernet_add, "<intfc> | sw_if_index <nn> remote_mac <mac-address> sub_id <id>") \
_(p2p_ethernet_del, "<intfc> | sw_if_index <nn> remote_mac <mac-address>") \
_(lldp_config, "system-name <name> tx-hold <nn> tx-interval <nn>") \
_(sw_interface_set_lldp, "<intfc> | sw_if_index <nn> [port-desc <description>] [disable]")
_(sw_interface_set_lldp, "<intfc> | sw_if_index <nn> [port-desc <description>] [disable]") \
_(tcp_configure_src_addresses, "<ip4|6>first-<ip4|6>last [vrf <id>]")
/* List of command functions, CLI names map directly to functions */
#define foreach_cli_function \
+3
View File
@@ -466,6 +466,7 @@ endif
# Layer 4 protocol: tcp
########################################
libvnet_la_SOURCES += \
vnet/tcp/tcp_api.c \
vnet/tcp/tcp_format.c \
vnet/tcp/tcp_pg.c \
vnet/tcp/tcp_syn_filter4.c \
@@ -485,6 +486,8 @@ nobase_include_HEADERS += \
vnet/tcp/tcp_debug.h \
vnet/tcp/tcp.h
API_FILES += vnet/tcp/tcp.api
########################################
# Layer 4 protocol: udp
########################################
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2015-2016 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.
*/
/** \brief Configure TCP source addresses, for active-open TCP sessions
TCP src/dst ports are 16 bits, with the low-order 1024 ports
reserved. So, it's necessary to provide a considerable number of
source IP addresses if one wishes to initiate a large number of
connections.
Each of those addresses needs to have a receive adjacency -
either a /32 or a /128 - and vpp needs to answer (proxy) arps or
neighbor discovery requests for the addresses.
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_ipv6 - 1 for ipv6, 0 for ipv4
@param vrf_id - fib table / vrf id for local adjacencies
@param first_address - first address that TCP will use
@param last_address - last address that TCP will use
*/
autoreply define tcp_configure_src_addresses {
u32 client_index;
u32 context;
u8 is_ipv6;
u32 vrf_id;
u8 first_address[16];
u8 last_address[16];
};
+218 -12
View File
@@ -13,10 +13,17 @@
* limitations under the License.
*/
/**
* @file
* @brief TCP host stack utilities
*/
#include <vnet/tcp/tcp.h>
#include <vnet/session/session.h>
#include <vnet/fib/fib.h>
#include <vnet/dpo/load_balance.h>
#include <vnet/dpo/receive_dpo.h>
#include <vnet/ip/ip6_neighbor.h>
#include <math.h>
tcp_main_t tcp_main;
@@ -1347,6 +1354,7 @@ tcp_init (vlib_main_t * vm)
{
tcp_main_t *tm = vnet_get_tcp_main ();
tm->is_enabled = 0;
tcp_api_reference ();
return 0;
}
@@ -1375,15 +1383,191 @@ tcp_config_fn (vlib_main_t * vm, unformat_input_t * input)
VLIB_CONFIG_FUNCTION (tcp_config_fn, "tcp");
/**
* \brief Configure an ipv4 source address range
* @param vm vlib_main_t pointer
* @param start first ipv4 address in the source address range
* @param end last ipv4 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_v4_source_address_range (vlib_main_t * vm,
ip4_address_t * start,
ip4_address_t * end, u32 table_id)
{
tcp_main_t *tm = vnet_get_tcp_main ();
vnet_main_t *vnm = vnet_get_main ();
u32 start_host_byte_order, end_host_byte_order;
fib_prefix_t prefix;
vnet_sw_interface_t *si;
fib_node_index_t fei;
u32 fib_index = 0;
u32 sw_if_index;
int rv;
int vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
ip4_address_t * hi_addr, u32 fib_index,
int is_del);
memset (&prefix, 0, sizeof (prefix));
fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
if (fib_index == ~0)
return VNET_API_ERROR_NO_SUCH_FIB;
start_host_byte_order = clib_net_to_host_u32 (start->as_u32);
end_host_byte_order = clib_net_to_host_u32 (end->as_u32);
/* sanity check for reversed args or some such */
if ((end_host_byte_order - start_host_byte_order) > (10 << 10))
return VNET_API_ERROR_INVALID_ARGUMENT;
/* Lookup the last address, to identify the interface involved */
prefix.fp_len = 32;
prefix.fp_proto = FIB_PROTOCOL_IP4;
memcpy (&prefix.fp_addr.ip4, end, sizeof (ip4_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);
/* Enable proxy arp on the interface */
si = vnet_get_sw_interface (vnm, sw_if_index);
si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
/* Configure proxy arp across the range */
rv = vnet_proxy_arp_add_del (start, end, fib_index, 0 /* is_del */ );
if (rv)
return rv;
do
{
dpo_id_t dpo = DPO_INVALID;
vec_add1 (tm->ip4_src_addresses, start[0]);
/* Add local adjacencies for the range */
receive_dpo_add_or_lock (DPO_PROTO_IP4, ~0 /* sw_if_index */ ,
NULL, &dpo);
prefix.fp_len = 32;
prefix.fp_proto = FIB_PROTOCOL_IP4;
prefix.fp_addr.ip4.as_u32 = start->as_u32;
fib_table_entry_special_dpo_update (fib_index,
&prefix,
FIB_SOURCE_API,
FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
dpo_reset (&dpo);
start_host_byte_order++;
start->as_u32 = clib_host_to_net_u32 (start_host_byte_order);
}
while (start_host_byte_order <= end_host_byte_order);
return 0;
}
/**
* \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;
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)
{
tcp_main_t *tm = vnet_get_tcp_main ();
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)
{
@@ -1396,13 +1580,15 @@ tcp_src_address (vlib_main_t * vm,
v4set = 1;
}
else if (unformat (input, "%U - %U", unformat_ip6_address, &v6start,
unformat_ip4_address, &v6end))
unformat_ip6_address, &v6end))
v6set = 1;
else if (unformat (input, "%U", unformat_ip6_address, &v6start))
{
memcpy (&v6end, &v6start, sizeof (v4start));
v6set = 1;
}
else if (unformat (input, "fib-table %d", &table_id))
;
else
break;
}
@@ -1412,21 +1598,41 @@ tcp_src_address (vlib_main_t * vm,
if (v4set)
{
u32 tmp;
do
rv = tcp_configure_v4_source_address_range (vm, &v4start, &v4end,
table_id);
switch (rv)
{
vec_add1 (tm->ip4_src_addresses, v4start);
tmp = clib_net_to_host_u32 (v4start.as_u32);
tmp++;
v4start.as_u32 = clib_host_to_net_u32 (tmp);
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;
}
while (clib_host_to_net_u32 (v4start.as_u32) <=
clib_host_to_net_u32 (v4end.as_u32));
}
if (v6set)
{
clib_warning ("v6 src address list unimplemented...");
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;
}
+7 -1
View File
@@ -465,7 +465,13 @@ void tcp_connection_del (tcp_connection_t * tc);
int tcp_half_open_connection_cleanup (tcp_connection_t * tc);
tcp_connection_t *tcp_connection_new (u8 thread_index);
void tcp_connection_reset (tcp_connection_t * tc);
int tcp_configure_v4_source_address_range (vlib_main_t * vm,
ip4_address_t * start,
ip4_address_t * end, u32 table_id);
int tcp_configure_v6_source_address_range (vlib_main_t * vm,
ip6_address_t * start,
ip6_address_t * end, u32 table_id);
void tcp_api_reference (void);
u8 *format_tcp_connection_id (u8 * s, va_list * args);
u8 *format_tcp_connection (u8 * s, va_list * args);
u8 *format_tcp_scoreboard (u8 * s, va_list * args);
+119
View File
@@ -0,0 +1,119 @@
/*
*------------------------------------------------------------------
* tcp_api.c - vnet tcp-layer apis
*
* Copyright (c) 2017 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.
*------------------------------------------------------------------
*/
#include <vnet/vnet.h>
#include <vlibmemory/api.h>
#include <vnet/tcp/tcp.h>
#include <vnet/vnet_msg_enum.h>
#define vl_typedefs /* define message structures */
#include <vnet/vnet_all_api_h.h>
#undef vl_typedefs
#define vl_endianfun /* define message structures */
#include <vnet/vnet_all_api_h.h>
#undef vl_endianfun
/* instantiate all the print functions we know about */
#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
#define vl_printfun
#include <vnet/vnet_all_api_h.h>
#undef vl_printfun
#include <vlibapi/api_helper_macros.h>
#define foreach_tcp_api_msg \
_(TCP_CONFIGURE_SRC_ADDRESSES, tcp_configure_src_addresses)
static void
vl_api_tcp_configure_src_addresses_t_handler
(vl_api_tcp_configure_src_addresses_t * mp)
{
vlib_main_t *vm = vlib_get_main ();
vl_api_tcp_configure_src_addresses_reply_t *rmp;
u32 vrf_id;
int rv;
vrf_id = clib_net_to_host_u32 (mp->vrf_id);
if (mp->is_ipv6)
rv = tcp_configure_v6_source_address_range
(vm,
(ip6_address_t *) mp->first_address,
(ip6_address_t *) mp->last_address, vrf_id);
else
rv = tcp_configure_v4_source_address_range
(vm,
(ip4_address_t *) mp->first_address,
(ip4_address_t *) mp->last_address, vrf_id);
REPLY_MACRO (VL_API_TCP_CONFIGURE_SRC_ADDRESSES_REPLY);
}
#define vl_msg_name_crc_list
#include <vnet/tcp/tcp.api.h>
#undef vl_msg_name_crc_list
static void
setup_message_id_table (api_main_t * am)
{
#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
foreach_vl_msg_name_crc_tcp;
#undef _
}
static clib_error_t *
tcp_api_hookup (vlib_main_t * vm)
{
api_main_t *am = &api_main;
#define _(N,n) \
vl_msg_api_set_handlers(VL_API_##N, #n, \
vl_api_##n##_t_handler, \
vl_noop_handler, \
vl_api_##n##_t_endian, \
vl_api_##n##_t_print, \
sizeof(vl_api_##n##_t), 1);
foreach_tcp_api_msg;
#undef _
/*
* Set up the (msg_name, crc, message-id) table
*/
setup_message_id_table (am);
return 0;
}
VLIB_API_INIT_FUNCTION (tcp_api_hookup);
void
tcp_api_reference (void)
{
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+1
View File
@@ -58,6 +58,7 @@
#include <vnet/cop/cop.api.h>
#include <vnet/policer/policer.api.h>
#include <vnet/ethernet/p2p_ethernet.api.h>
#include <vnet/tcp/tcp.api.h>
/*
* fd.io coding-style-patch-verification: ON
+23 -1
View File
@@ -3007,6 +3007,27 @@ static void *vl_api_p2p_ethernet_del_t_print
FINISH;
}
static void *vl_api_tcp_configure_src_addresses_t_print
(vl_api_tcp_configure_src_addresses_t * mp, void *handle)
{
u8 *s;
s = format (0, "SCRIPT: tcp_configure_src_addresses ");
if (mp->is_ipv6)
s = format (s, "%U - %U ",
format_ip6_address, (ip6_address_t *) mp->first_address,
format_ip6_address, (ip6_address_t *) mp->last_address);
else
s = format (s, "%U - %U ",
format_ip4_address, (ip4_address_t *) mp->first_address,
format_ip4_address, (ip4_address_t *) mp->last_address);
if (mp->vrf_id)
s = format (s, "vrf %d ", ntohl (mp->vrf_id));
FINISH;
}
#define foreach_custom_print_no_arg_function \
_(lisp_eid_table_vni_dump) \
_(lisp_map_resolver_dump) \
@@ -3191,7 +3212,8 @@ _(FEATURE_ENABLE_DISABLE, feature_enable_disable) \
_(SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del) \
_(SW_INTERFACE_SET_MTU, sw_interface_set_mtu) \
_(P2P_ETHERNET_ADD, p2p_ethernet_add) \
_(P2P_ETHERNET_DEL, p2p_ethernet_del)
_(P2P_ETHERNET_DEL, p2p_ethernet_del) \
_(TCP_CONFIGURE_SRC_ADDRESSES, tcp_configure_src_addresses)
void
vl_msg_api_custom_dump_configure (api_main_t * am)
{