From 724b8159feeb3b4af80cd1e64233d0fae7c54590 Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Tue, 4 Oct 2016 03:23:43 -0700 Subject: VPP-453: SNAT delete and dump addresses Delete operation for SNAT addresses Dump API for SNAT addresses Change-Id: I84e888d20286ec2523fbd4ca7e68e3eef5927984 Signed-off-by: Matus Fabian --- plugins/snat-plugin/snat/snat.api | 24 ++++- plugins/snat-plugin/snat/snat.c | 178 ++++++++++++++++++++++++++++++++--- plugins/snat-plugin/snat/snat_test.c | 67 ++++++++++--- 3 files changed, 243 insertions(+), 26 deletions(-) diff --git a/plugins/snat-plugin/snat/snat.api b/plugins/snat-plugin/snat/snat.api index daacf9ff624..b2a21cf2b64 100644 --- a/plugins/snat-plugin/snat/snat.api +++ b/plugins/snat-plugin/snat/snat.api @@ -20,12 +20,13 @@ * called through a shared memory interface. */ -/** \brief Add S-NAT address range +/** \brief Add/del S-NAT address range @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_ip4 - 1 if address type is IPv4 @first_ip_address - first IP address @last_ip_address - last IP address + @is_add - 1 if add, 0 if delete */ define snat_add_address_range { u32 client_index; @@ -33,6 +34,7 @@ define snat_add_address_range { u8 is_ip4; u8 first_ip_address[16]; u8 last_ip_address[16]; + u8 is_add; }; /** \brief Add S-NAT address range reply @@ -45,6 +47,26 @@ define snat_add_address_range_reply { i32 retval; }; +/** \brief Dump S-NAT addresses + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_address_dump { + u32 client_index; + u32 context; +}; + +/** \brief S-NAT address details response + @param context - sender context, to match reply w/ request + @param is_ip4 - 1 if address type is IPv4 + @param ip_address - IP address +*/ +define snat_address_details { + u32 context; + u8 is_ip4; + u8 ip_address[16]; +}; + /** \brief Enable/disable S-NAT feature on the interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/plugins/snat-plugin/snat/snat.c b/plugins/snat-plugin/snat/snat.c index 3fd9ecb41b7..8360db5ee42 100644 --- a/plugins/snat-plugin/snat/snat.c +++ b/plugins/snat-plugin/snat/snat.c @@ -207,6 +207,84 @@ void snat_add_address (snat_main_t *sm, ip4_address_t *addr) } +static int is_snat_address_used_in_static_mapping (snat_main_t *sm, + ip4_address_t addr) +{ + snat_static_mapping_t *m; + pool_foreach (m, sm->static_mappings, + ({ + if (m->external_addr.as_u32 == addr.as_u32) + return 1; + })); + + return 0; +} + +int snat_del_address (snat_main_t *sm, ip4_address_t addr) +{ + clib_warning("%U", format_ip4_address, &addr); + snat_address_t *a = 0; + snat_session_t *ses; + u32 *ses_to_be_removed = 0, *ses_index; + clib_bihash_kv_8_8_t kv, value; + snat_user_key_t user_key; + snat_user_t *u; + + int i; + + /* Find SNAT address */ + for (i=0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].addr.as_u32 == addr.as_u32) + { + a = sm->addresses + i; + break; + } + } + if (!a) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + /* Check if address is used in some static mapping */ + if (is_snat_address_used_in_static_mapping(sm, addr)) + { + clib_warning ("address used in static mapping"); + return VNET_API_ERROR_UNSPECIFIED; + } + + /* Delete sessions using address */ + if (a->busy_ports) + { + pool_foreach (ses, sm->sessions, ({ + if (ses->out2in.addr.as_u32 == addr.as_u32) + { + vec_add1 (ses_to_be_removed, ses - sm->sessions); + kv.key = ses->in2out.as_u64; + clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0); + kv.key = ses->out2in.as_u64; + clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0); + clib_dlist_remove (sm->list_pool, ses->per_user_index); + user_key.addr = ses->in2out.addr; + user_key.fib_index = ses->in2out.fib_index; + kv.key = user_key.as_u64; + if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) + { + u = pool_elt_at_index (sm->users, value.value); + u->nsessions--; + } + } + })); + + vec_foreach (ses_index, ses_to_be_removed) + pool_put_index (sm->sessions, ses_index[0]); + + vec_free (ses_to_be_removed); + } + + vec_del1 (sm->addresses, i); + + return 0; +} + static void increment_v4_address (ip4_address_t * a) { u32 v; @@ -490,7 +568,14 @@ vl_api_snat_add_address_range_t_handler for (i = 0; i < count; i++) { - snat_add_address (sm, &this_addr); + if (mp->is_add) + snat_add_address (sm, &this_addr); + else + rv = snat_del_address (sm, this_addr); + + if (rv) + goto send_reply; + increment_v4_address (&this_addr); } @@ -512,6 +597,49 @@ static void *vl_api_snat_add_address_range_t_print FINISH; } +static void +send_snat_address_details +(snat_address_t * a, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_snat_address_details_t *rmp; + snat_main_t * sm = &snat_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base); + rmp->is_ip4 = 1; + clib_memcpy (rmp->ip_address, &(a->addr), 4); + rmp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void +vl_api_snat_address_dump_t_handler +(vl_api_snat_address_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + snat_main_t * sm = &snat_main; + snat_address_t * a; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + vec_foreach (a, sm->addresses) + send_snat_address_details (a, q, mp->context); +} + +static void *vl_api_snat_address_dump_t_print +(vl_api_snat_address_dump_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_address_dump "); + + FINISH; +} + static void vl_api_snat_interface_add_del_feature_t_handler (vl_api_snat_interface_add_del_feature_t * mp) @@ -735,7 +863,8 @@ _(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature) \ _(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping) \ _(SNAT_CONTROL_PING, snat_control_ping) \ _(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump) \ -_(SNAT_SHOW_CONFIG, snat_show_config) +_(SNAT_SHOW_CONFIG, snat_show_config) \ +_(SNAT_ADDRESS_DUMP, snat_address_dump) /* Set up the API message handling tables */ static clib_error_t * @@ -921,20 +1050,27 @@ add_address_command_fn (vlib_main_t * vm, ip4_address_t start_addr, end_addr, this_addr; u32 start_host_order, end_host_order; int i, count; + int is_add = 1; + int rv = 0; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; - if (unformat (line_input, "%U - %U", - unformat_ip4_address, &start_addr, - unformat_ip4_address, &end_addr)) - ; - else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) - end_addr = start_addr; - else - return clib_error_return (0, "unknown input '%U'", format_unformat_error, - input); + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U - %U", + unformat_ip4_address, &start_addr, + unformat_ip4_address, &end_addr)) + ; + else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) + end_addr = start_addr; + else if (unformat (line_input, "del")) + is_add = 0; + else + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } unformat_free (line_input); if (sm->static_mapping_only) @@ -958,7 +1094,23 @@ add_address_command_fn (vlib_main_t * vm, for (i = 0; i < count; i++) { - snat_add_address (sm, &this_addr); + if (is_add) + snat_add_address (sm, &this_addr); + else + rv = snat_del_address (sm, this_addr); + + switch (rv) + { + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "S-NAT address not exist."); + break; + case VNET_API_ERROR_UNSPECIFIED: + return clib_error_return (0, "S-NAT address used in static mapping."); + break; + default: + break; + } + increment_v4_address (&this_addr); } @@ -967,7 +1119,7 @@ add_address_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (add_address_command, static) = { .path = "snat add address", - .short_help = "snat add addresses [- ]", + .short_help = "snat add addresses [- ] [del]", .function = add_address_command_fn, }; diff --git a/plugins/snat-plugin/snat/snat_test.c b/plugins/snat-plugin/snat/snat_test.c index 453c63f28bd..29577e92607 100644 --- a/plugins/snat-plugin/snat/snat_test.c +++ b/plugins/snat-plugin/snat/snat_test.c @@ -89,7 +89,8 @@ _(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY, \ _(SNAT_ADD_STATIC_MAPPING_REPLY, snat_add_static_mapping_reply) \ _(SNAT_CONTROL_PING_REPLY, snat_control_ping_reply) \ _(SNAT_STATIC_MAPPING_DETAILS, snat_static_mapping_details) \ -_(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply) +_(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply) \ +_(SNAT_ADDRESS_DETAILS, snat_address_details) /* M: construct, but don't yet send a message */ #define M(T,t) \ @@ -134,18 +135,24 @@ static int api_snat_add_address_range (vat_main_t * vam) ip4_address_t start_addr, end_addr; u32 start_host_order, end_host_order; vl_api_snat_add_address_range_t * mp; + u8 is_add = 1; int count; - if (unformat (i, "%U - %U", - unformat_ip4_address, &start_addr, - unformat_ip4_address, &end_addr)) - ; - else if (unformat (i, "%U", unformat_ip4_address, &start_addr)) - end_addr = start_addr; - else + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; + if (unformat (i, "%U - %U", + unformat_ip4_address, &start_addr, + unformat_ip4_address, &end_addr)) + ; + else if (unformat (i, "%U", unformat_ip4_address, &start_addr)) + end_addr = start_addr; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning("unknown input '%U'", format_unformat_error, i); + return -99; + } } start_host_order = clib_host_to_net_u32 (start_addr.as_u32); @@ -172,6 +179,7 @@ static int api_snat_add_address_range (vat_main_t * vam) memcpy (mp->first_ip_address, &start_addr, 4); memcpy (mp->last_ip_address, &end_addr, 4); mp->is_ip4 = 1; + mp->is_add = is_add; S; W; @@ -395,18 +403,53 @@ static int api_snat_show_config(vat_main_t * vam) return 0; } +static void vl_api_snat_address_details_t_handler + (vl_api_snat_address_details_t *mp) +{ + snat_test_main_t * sm = &snat_test_main; + vat_main_t *vam = sm->vat_main; + + fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address); +} + +static int api_snat_address_dump(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + f64 timeout; + vl_api_snat_address_dump_t * mp; + + if (vam->json_output) + { + clib_warning ("JSON output not supported for snat_address_dump"); + return -99; + } + + M(SNAT_ADDRESS_DUMP, snat_address_dump); + S; + /* Use a control ping for synchronization */ + { + vl_api_snat_control_ping_t *mp; + M (SNAT_CONTROL_PING, snat_control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + /* * List of messages that the api test plugin sends, * and that the data plane plugin processes */ #define foreach_vpe_api_msg \ -_(snat_add_address_range, " [- [- | sw_if_index [in] [out] [del]") \ _(snat_add_static_mapping, "local_addr external_addr " \ "[local_port ] [external_port ] [vrf ] [del]") \ _(snat_static_mapping_dump, "") \ -_(snat_show_config, "") +_(snat_show_config, "") \ +_(snat_address_dump, "") void vat_api_hookup (vat_main_t *vam) { -- cgit 1.2.3-korg