diff options
Diffstat (limited to 'src/plugins/snat')
-rw-r--r-- | src/plugins/snat/in2out.c | 3454 | ||||
-rw-r--r-- | src/plugins/snat/nat64.c | 858 | ||||
-rw-r--r-- | src/plugins/snat/nat64.h | 322 | ||||
-rw-r--r-- | src/plugins/snat/nat64_cli.c | 983 | ||||
-rw-r--r-- | src/plugins/snat/nat64_db.c | 603 | ||||
-rw-r--r-- | src/plugins/snat/nat64_db.h | 307 | ||||
-rw-r--r-- | src/plugins/snat/nat64_doc.md | 73 | ||||
-rw-r--r-- | src/plugins/snat/nat64_in2out.c | 1118 | ||||
-rw-r--r-- | src/plugins/snat/nat64_out2in.c | 494 | ||||
-rw-r--r-- | src/plugins/snat/out2in.c | 2294 | ||||
-rw-r--r-- | src/plugins/snat/snat.api | 897 | ||||
-rw-r--r-- | src/plugins/snat/snat.c | 2842 | ||||
-rw-r--r-- | src/plugins/snat/snat.h | 541 | ||||
-rw-r--r-- | src/plugins/snat/snat_all_api_h.h | 19 | ||||
-rw-r--r-- | src/plugins/snat/snat_api.c | 1970 | ||||
-rw-r--r-- | src/plugins/snat/snat_det.c | 158 | ||||
-rw-r--r-- | src/plugins/snat/snat_det.h | 196 | ||||
-rw-r--r-- | src/plugins/snat/snat_ipfix_logging.c | 835 | ||||
-rw-r--r-- | src/plugins/snat/snat_ipfix_logging.h | 79 | ||||
-rw-r--r-- | src/plugins/snat/snat_msg_enum.h | 31 | ||||
-rw-r--r-- | src/plugins/snat/snat_test.c | 1167 |
21 files changed, 0 insertions, 19241 deletions
diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c deleted file mode 100644 index abe0d9dbe87..00000000000 --- a/src/plugins/snat/in2out.c +++ /dev/null @@ -1,3454 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <vlib/vlib.h> -#include <vnet/vnet.h> -#include <vnet/pg/pg.h> -#include <vnet/handoff.h> - -#include <vnet/ip/ip.h> -#include <vnet/ethernet/ethernet.h> -#include <vnet/fib/ip4_fib.h> -#include <snat/snat.h> -#include <snat/snat_ipfix_logging.h> -#include <snat/snat_det.h> - -#include <vppinfra/hash.h> -#include <vppinfra/error.h> -#include <vppinfra/elog.h> - -typedef struct { - u32 sw_if_index; - u32 next_index; - u32 session_index; - u32 is_slow_path; -} snat_in2out_trace_t; - -typedef struct { - u32 next_worker_index; - u8 do_handoff; -} snat_in2out_worker_handoff_trace_t; - -/* packet trace format function */ -static u8 * format_snat_in2out_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *); - char * tag; - - tag = t->is_slow_path ? "SNAT_IN2OUT_SLOW_PATH" : "SNAT_IN2OUT_FAST_PATH"; - - s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag, - t->sw_if_index, t->next_index, t->session_index); - - return s; -} - -static u8 * format_snat_in2out_fast_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *); - - s = format (s, "SANT_IN2OUT_FAST: sw_if_index %d, next index %d", - t->sw_if_index, t->next_index); - - return s; -} - -static u8 * format_snat_in2out_worker_handoff_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - snat_in2out_worker_handoff_trace_t * t = - va_arg (*args, snat_in2out_worker_handoff_trace_t *); - char * m; - - m = t->do_handoff ? "next worker" : "same worker"; - s = format (s, "SNAT_IN2OUT_WORKER_HANDOFF: %s %d", m, t->next_worker_index); - - return s; -} - -vlib_node_registration_t snat_in2out_node; -vlib_node_registration_t snat_in2out_slowpath_node; -vlib_node_registration_t snat_in2out_fast_node; -vlib_node_registration_t snat_in2out_worker_handoff_node; -vlib_node_registration_t snat_det_in2out_node; -vlib_node_registration_t snat_in2out_output_node; -vlib_node_registration_t snat_in2out_output_slowpath_node; -vlib_node_registration_t snat_in2out_output_worker_handoff_node; -vlib_node_registration_t snat_hairpin_dst_node; -vlib_node_registration_t snat_hairpin_src_node; - - -#define foreach_snat_in2out_error \ -_(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ -_(IN2OUT_PACKETS, "Good in2out packets processed") \ -_(OUT_OF_PORTS, "Out of ports") \ -_(BAD_OUTSIDE_FIB, "Outside VRF ID not found") \ -_(BAD_ICMP_TYPE, "unsupported ICMP type") \ -_(NO_TRANSLATION, "No translation") - -typedef enum { -#define _(sym,str) SNAT_IN2OUT_ERROR_##sym, - foreach_snat_in2out_error -#undef _ - SNAT_IN2OUT_N_ERROR, -} snat_in2out_error_t; - -static char * snat_in2out_error_strings[] = { -#define _(sym,string) string, - foreach_snat_in2out_error -#undef _ -}; - -typedef enum { - SNAT_IN2OUT_NEXT_LOOKUP, - SNAT_IN2OUT_NEXT_DROP, - SNAT_IN2OUT_NEXT_ICMP_ERROR, - SNAT_IN2OUT_NEXT_SLOW_PATH, - SNAT_IN2OUT_N_NEXT, -} snat_in2out_next_t; - -typedef enum { - SNAT_HAIRPIN_SRC_NEXT_DROP, - SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT, - SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH, - SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT, - SNAT_HAIRPIN_SRC_N_NEXT, -} snat_hairpin_next_t; - -/** - * @brief Check if packet should be translated - * - * Packets aimed at outside interface and external addresss with active session - * should be translated. - * - * @param sm SNAT main - * @param rt SNAT runtime data - * @param sw_if_index0 index of the inside interface - * @param ip0 IPv4 header - * @param proto0 SNAT protocol - * @param rx_fib_index0 RX FIB index - * - * @returns 0 if packet should be translated otherwise 1 - */ -static inline int -snat_not_translate_fast (snat_main_t * sm, vlib_node_runtime_t *node, - u32 sw_if_index0, ip4_header_t * ip0, u32 proto0, - u32 rx_fib_index0) -{ - fib_node_index_t fei = FIB_NODE_INDEX_INVALID; - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4.as_u32 = ip0->dst_address.as_u32, - }, - }; - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, - ip0->dst_address.as_u32))) - return 1; - - fei = fib_table_lookup (rx_fib_index0, &pfx); - if (FIB_NODE_INDEX_INVALID != fei) - { - u32 sw_if_index = fib_entry_get_resolving_interface (fei); - if (sw_if_index == ~0) - { - fei = fib_table_lookup (sm->outside_fib_index, &pfx); - if (FIB_NODE_INDEX_INVALID != fei) - sw_if_index = fib_entry_get_resolving_interface (fei); - } - snat_interface_t *i; - pool_foreach (i, sm->interfaces, - ({ - /* NAT packet aimed at outside interface */ - if ((i->is_inside == 0) && (sw_if_index == i->sw_if_index)) - return 0; - })); - } - - return 1; -} - -static inline int -snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node, - u32 sw_if_index0, ip4_header_t * ip0, u32 proto0, - u32 rx_fib_index0) -{ - udp_header_t * udp0 = ip4_next_header (ip0); - snat_session_key_t key0, sm0; - clib_bihash_kv_8_8_t kv0, value0; - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = sm->outside_fib_index; - kv0.key = key0.as_u64; - - /* NAT packet aimed at external address if */ - /* has active sessions */ - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* or is static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0)) - return 0; - } - else - return 0; - - return snat_not_translate_fast(sm, node, sw_if_index0, ip0, proto0, - rx_fib_index0); -} - -static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, - ip4_header_t * ip0, - u32 rx_fib_index0, - snat_session_key_t * key0, - snat_session_t ** sessionp, - vlib_node_runtime_t * node, - u32 next0, - u32 thread_index) -{ - snat_user_t *u; - snat_user_key_t user_key; - snat_session_t *s; - clib_bihash_kv_8_8_t kv0, value0; - u32 oldest_per_user_translation_list_index; - dlist_elt_t * oldest_per_user_translation_list_elt; - dlist_elt_t * per_user_translation_list_elt; - dlist_elt_t * per_user_list_head_elt; - u32 session_index; - snat_session_key_t key1; - u32 address_index = ~0; - u32 outside_fib_index; - uword * p; - snat_worker_key_t worker_by_out_key; - - p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id); - if (! p) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB]; - return SNAT_IN2OUT_NEXT_DROP; - } - outside_fib_index = p[0]; - - key1.protocol = key0->protocol; - user_key.addr = ip0->src_address; - user_key.fib_index = rx_fib_index0; - kv0.key = user_key.as_u64; - - /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) - { - /* no, make a new one */ - pool_get (sm->per_thread_data[thread_index].users, u); - memset (u, 0, sizeof (*u)); - u->addr = ip0->src_address; - u->fib_index = rx_fib_index0; - - pool_get (sm->per_thread_data[thread_index].list_pool, per_user_list_head_elt); - - u->sessions_per_user_list_head_index = per_user_list_head_elt - - sm->per_thread_data[thread_index].list_pool; - - clib_dlist_init (sm->per_thread_data[thread_index].list_pool, - u->sessions_per_user_list_head_index); - - kv0.value = u - sm->per_thread_data[thread_index].users; - - /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); - } - else - { - u = pool_elt_at_index (sm->per_thread_data[thread_index].users, - value0.value); - } - - /* Over quota? Recycle the least recently used dynamic translation */ - if (u->nsessions >= sm->max_translations_per_user) - { - /* Remove the oldest dynamic translation */ - do { - oldest_per_user_translation_list_index = - clib_dlist_remove_head (sm->per_thread_data[thread_index].list_pool, - u->sessions_per_user_list_head_index); - - ASSERT (oldest_per_user_translation_list_index != ~0); - - /* add it back to the end of the LRU list */ - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - u->sessions_per_user_list_head_index, - oldest_per_user_translation_list_index); - /* Get the list element */ - oldest_per_user_translation_list_elt = - pool_elt_at_index (sm->per_thread_data[thread_index].list_pool, - oldest_per_user_translation_list_index); - - /* Get the session index from the list element */ - session_index = oldest_per_user_translation_list_elt->value; - - /* Get the session */ - s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - session_index); - } while (snat_is_session_static (s)); - - if (snat_is_unk_proto_session (s)) - { - clib_bihash_kv_16_8_t up_kv; - snat_unk_proto_ses_key_t key; - - /* Remove from lookup tables */ - key.l_addr = s->in2out.addr; - key.r_addr = s->ext_host_addr; - key.fib_index = s->in2out.fib_index; - key.proto = s->in2out.port; - up_kv.key[0] = key.as_u64[0]; - up_kv.key[1] = key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_unk_proto, &up_kv, 0)) - clib_warning ("in2out key del failed"); - - key.l_addr = s->out2in.addr; - key.fib_index = s->out2in.fib_index; - up_kv.key[0] = key.as_u64[0]; - up_kv.key[1] = key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->out2in_unk_proto, &up_kv, 0)) - clib_warning ("out2in key del failed"); - } - else - { - /* Remove in2out, out2in keys */ - kv0.key = s->in2out.as_u64; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 0 /* is_add */)) - clib_warning ("in2out key delete failed"); - kv0.key = s->out2in.as_u64; - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 0 /* is_add */)) - clib_warning ("out2in key delete failed"); - - /* log NAT event */ - snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32, - s->out2in.addr.as_u32, - s->in2out.protocol, - s->in2out.port, - s->out2in.port, - s->in2out.fib_index); - - snat_free_outside_address_and_port - (sm, &s->out2in, s->outside_address_index); - } - s->outside_address_index = ~0; - - if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, thread_index, - &key1, &address_index)) - { - ASSERT(0); - - b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; - return SNAT_IN2OUT_NEXT_DROP; - } - s->outside_address_index = address_index; - } - else - { - u8 static_mapping = 1; - - /* First try to match static mapping by local address and port */ - if (snat_static_mapping_match (sm, *key0, &key1, 0, 0)) - { - static_mapping = 0; - /* Try to create dynamic translation */ - if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, - thread_index, &key1, - &address_index)) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; - return SNAT_IN2OUT_NEXT_DROP; - } - } - - /* Create a new session */ - pool_get (sm->per_thread_data[thread_index].sessions, s); - memset (s, 0, sizeof (*s)); - - s->outside_address_index = address_index; - - if (static_mapping) - { - u->nstaticsessions++; - s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - } - else - { - u->nsessions++; - } - - /* Create list elts */ - pool_get (sm->per_thread_data[thread_index].list_pool, - per_user_translation_list_elt); - clib_dlist_init (sm->per_thread_data[thread_index].list_pool, - per_user_translation_list_elt - - sm->per_thread_data[thread_index].list_pool); - - per_user_translation_list_elt->value = - s - sm->per_thread_data[thread_index].sessions; - s->per_user_index = per_user_translation_list_elt - - sm->per_thread_data[thread_index].list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s->per_user_list_head_index, - per_user_translation_list_elt - - sm->per_thread_data[thread_index].list_pool); - } - - s->in2out = *key0; - s->out2in = key1; - s->out2in.protocol = key0->protocol; - s->out2in.fib_index = outside_fib_index; - s->ext_host_addr.as_u32 = ip0->dst_address.as_u32; - *sessionp = s; - - /* Add to translation hashes */ - kv0.key = s->in2out.as_u64; - kv0.value = s - sm->per_thread_data[thread_index].sessions; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) - clib_warning ("in2out key add failed"); - - kv0.key = s->out2in.as_u64; - kv0.value = s - sm->per_thread_data[thread_index].sessions; - - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) - clib_warning ("out2in key add failed"); - - /* Add to translated packets worker lookup */ - worker_by_out_key.addr = s->out2in.addr; - worker_by_out_key.port = s->out2in.port; - worker_by_out_key.fib_index = s->out2in.fib_index; - kv0.key = worker_by_out_key.as_u64; - kv0.value = thread_index; - clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1); - - /* log NAT event */ - snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32, - s->out2in.addr.as_u32, - s->in2out.protocol, - s->in2out.port, - s->out2in.port, - s->in2out.fib_index); - return next0; -} - -static_always_inline -snat_in2out_error_t icmp_get_key(ip4_header_t *ip0, - snat_session_key_t *p_key0) -{ - icmp46_header_t *icmp0; - snat_session_key_t key0; - icmp_echo_header_t *echo0, *inner_echo0 = 0; - ip4_header_t *inner_ip0 = 0; - void *l4_header = 0; - icmp46_header_t *inner_icmp0; - - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - echo0 = (icmp_echo_header_t *)(icmp0+1); - - if (!icmp_is_error_message (icmp0)) - { - key0.protocol = SNAT_PROTOCOL_ICMP; - key0.addr = ip0->src_address; - key0.port = echo0->identifier; - } - else - { - inner_ip0 = (ip4_header_t *)(echo0+1); - l4_header = ip4_next_header (inner_ip0); - key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol); - key0.addr = inner_ip0->dst_address; - switch (key0.protocol) - { - case SNAT_PROTOCOL_ICMP: - inner_icmp0 = (icmp46_header_t*)l4_header; - inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); - key0.port = inner_echo0->identifier; - break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - key0.port = ((tcp_udp_header_t*)l4_header)->dst_port; - break; - default: - return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL; - } - } - *p_key0 = key0; - return -1; /* success */ -} - -/** - * Get address and port values to be used for packet SNAT translation - * and create session if needed - * - * @param[in,out] sm SNAT main - * @param[in,out] node SNAT node runtime - * @param[in] thread_index thread index - * @param[in,out] b0 buffer containing packet to be translated - * @param[out] p_proto protocol used for matching - * @param[out] p_value address and port after NAT translation - * @param[out] p_dont_translate if packet should not be translated - * @param d optional parameter - * @param e optional parameter - */ -u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e) -{ - ip4_header_t *ip0; - icmp46_header_t *icmp0; - u32 sw_if_index0; - u32 rx_fib_index0; - snat_session_key_t key0; - snat_session_t *s0 = 0; - u8 dont_translate = 0; - clib_bihash_kv_8_8_t kv0, value0; - u32 next0 = ~0; - int err; - u32 iph_offset0 = 0; - - if (PREDICT_FALSE(vnet_buffer(b0)->sw_if_index[VLIB_TX] != ~0)) - { - iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length; - } - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + iph_offset0); - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); - - err = icmp_get_key (ip0, &key0); - if (err != -1) - { - b0->error = node->errors[err]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0)) - { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, ip0, - IP_PROTOCOL_ICMP, rx_fib_index0) && - vnet_buffer(b0)->sw_if_index[VLIB_TX] == ~0)) - { - dont_translate = 1; - goto out; - } - - if (PREDICT_FALSE(icmp_is_error_message (icmp0))) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - - next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, thread_index); - - if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) - goto out; - } - else - { - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request && - icmp0->type != ICMP4_echo_reply && - !icmp_is_error_message (icmp0))) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); - } - -out: - *p_proto = key0.protocol; - if (s0) - *p_value = s0->out2in; - *p_dont_translate = dont_translate; - if (d) - *(snat_session_t**)d = s0; - return next0; -} - -/** - * Get address and port values to be used for packet SNAT translation - * - * @param[in] sm SNAT main - * @param[in,out] node SNAT node runtime - * @param[in] thread_index thread index - * @param[in,out] b0 buffer containing packet to be translated - * @param[out] p_proto protocol used for matching - * @param[out] p_value address and port after NAT translation - * @param[out] p_dont_translate if packet should not be translated - * @param d optional parameter - * @param e optional parameter - */ -u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e) -{ - ip4_header_t *ip0; - icmp46_header_t *icmp0; - u32 sw_if_index0; - u32 rx_fib_index0; - snat_session_key_t key0; - snat_session_key_t sm0; - u8 dont_translate = 0; - u8 is_addr_only; - u32 next0 = ~0; - int err; - - ip0 = vlib_buffer_get_current (b0); - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); - - err = icmp_get_key (ip0, &key0); - if (err != -1) - { - b0->error = node->errors[err]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out2; - } - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only)) - { - if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0, - IP_PROTOCOL_ICMP, rx_fib_index0))) - { - dont_translate = 1; - goto out; - } - - if (icmp_is_error_message (icmp0)) - { - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - - b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request && - (icmp0->type != ICMP4_echo_reply || !is_addr_only) && - !icmp_is_error_message (icmp0))) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - -out: - *p_value = sm0; -out2: - *p_proto = key0.protocol; - *p_dont_translate = dont_translate; - return next0; -} - -static inline u32 icmp_in2out (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - u32 rx_fib_index0, - vlib_node_runtime_t * node, - u32 next0, - u32 thread_index, - void *d, - void *e) -{ - snat_session_key_t sm0; - u8 protocol; - icmp_echo_header_t *echo0, *inner_echo0 = 0; - ip4_header_t *inner_ip0; - void *l4_header = 0; - icmp46_header_t *inner_icmp0; - u8 dont_translate; - u32 new_addr0, old_addr0; - u16 old_id0, new_id0; - ip_csum_t sum0; - u16 checksum0; - u32 next0_tmp; - - echo0 = (icmp_echo_header_t *)(icmp0+1); - - next0_tmp = sm->icmp_match_in2out_cb(sm, node, thread_index, b0, - &protocol, &sm0, &dont_translate, d, e); - if (next0_tmp != ~0) - next0 = next0_tmp; - if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate) - goto out; - - sum0 = ip_incremental_checksum (0, icmp0, - ntohs(ip0->length) - ip4_header_bytes (ip0)); - checksum0 = ~ip_csum_fold (sum0); - if (PREDICT_FALSE(checksum0 != 0 && checksum0 != 0xffff)) - { - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - - old_addr0 = ip0->src_address.as_u32; - new_addr0 = ip0->src_address.as_u32 = sm0.addr.as_u32; - if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (!icmp_is_error_message (icmp0)) - { - new_id0 = sm0.port; - if (PREDICT_FALSE(new_id0 != echo0->identifier)) - { - old_id0 = echo0->identifier; - new_id0 = sm0.port; - echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier); - icmp0->checksum = ip_csum_fold (sum0); - } - } - else - { - inner_ip0 = (ip4_header_t *)(echo0+1); - l4_header = ip4_next_header (inner_ip0); - - if (!ip4_header_checksum_is_valid (inner_ip0)) - { - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - - old_addr0 = inner_ip0->dst_address.as_u32; - inner_ip0->dst_address = sm0.addr; - new_addr0 = inner_ip0->dst_address.as_u32; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - dst_address /* changed member */); - icmp0->checksum = ip_csum_fold (sum0); - - switch (protocol) - { - case SNAT_PROTOCOL_ICMP: - inner_icmp0 = (icmp46_header_t*)l4_header; - inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); - - old_id0 = inner_echo0->identifier; - new_id0 = sm0.port; - inner_echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier); - icmp0->checksum = ip_csum_fold (sum0); - break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - old_id0 = ((tcp_udp_header_t*)l4_header)->dst_port; - new_id0 = sm0.port; - ((tcp_udp_header_t*)l4_header)->dst_port = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t, - dst_port); - icmp0->checksum = ip_csum_fold (sum0); - break; - default: - ASSERT(0); - } - } - -out: - return next0; -} - -/** - * @brief Hairpinning - * - * Hairpinning allows two endpoints on the internal side of the NAT to - * communicate even if they only use each other's external IP addresses - * and ports. - * - * @param sm SNAT main. - * @param b0 Vlib buffer. - * @param ip0 IP header. - * @param udp0 UDP header. - * @param tcp0 TCP header. - * @param proto0 SNAT protocol. - */ -static inline void -snat_hairpinning (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - udp_header_t * udp0, - tcp_header_t * tcp0, - u32 proto0) -{ - snat_session_key_t key0, sm0; - snat_worker_key_t k0; - snat_session_t * s0; - clib_bihash_kv_8_8_t kv0, value0; - ip_csum_t sum0; - u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si; - u16 new_dst_port0, old_dst_port0; - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = sm->outside_fib_index; - kv0.key = key0.as_u64; - - /* Check if destination is in active sessions */ - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* or static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0)) - { - new_dst_addr0 = sm0.addr.as_u32; - new_dst_port0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - } - } - else - { - si = value0.value; - if (sm->num_workers > 1) - { - k0.addr = ip0->dst_address; - k0.port = udp0->dst_port; - k0.fib_index = sm->outside_fib_index; - kv0.key = k0.as_u64; - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) - ASSERT(0); - else - ti = value0.value; - } - else - ti = sm->num_workers; - - s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si); - new_dst_addr0 = s0->in2out.addr.as_u32; - new_dst_port0 = s0->in2out.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - } - - /* Destination is behind the same NAT, use internal address and port */ - if (new_dst_addr0) - { - old_dst_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_dst_addr0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - ip0->checksum = ip_csum_fold (sum0); - - old_dst_port0 = tcp0->dst; - if (PREDICT_TRUE(new_dst_port0 != old_dst_port0)) - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - tcp0->dst = new_dst_port0; - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0, - ip4_header_t /* cheat */, length); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - udp0->dst_port = new_dst_port0; - udp0->checksum = 0; - } - } - else - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - tcp0->checksum = ip_csum_fold(sum0); - } - } - } -} - -static inline void -snat_icmp_hairpinning (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0) -{ - snat_session_key_t key0, sm0; - clib_bihash_kv_8_8_t kv0, value0; - snat_worker_key_t k0; - u32 new_dst_addr0 = 0, old_dst_addr0, si, ti = 0; - ip_csum_t sum0; - snat_session_t *s0; - - if (!icmp_is_error_message (icmp0)) - { - icmp_echo_header_t *echo0 = (icmp_echo_header_t *)(icmp0+1); - u16 icmp_id0 = echo0->identifier; - key0.addr = ip0->dst_address; - key0.port = icmp_id0; - key0.protocol = SNAT_PROTOCOL_ICMP; - key0.fib_index = sm->outside_fib_index; - kv0.key = key0.as_u64; - - /* Check if destination is in active sessions */ - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* or static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0)) - { - new_dst_addr0 = sm0.addr.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - } - } - else - { - si = value0.value; - if (sm->num_workers > 1) - { - k0.addr = ip0->dst_address; - k0.port = icmp_id0; - k0.fib_index = sm->outside_fib_index; - kv0.key = k0.as_u64; - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) - ASSERT(0); - else - ti = value0.value; - } - else - ti = sm->num_workers; - - s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si); - new_dst_addr0 = s0->in2out.addr.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - echo0->identifier = s0->in2out.port; - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, icmp_id0, s0->in2out.port, - icmp_echo_header_t, identifier); - icmp0->checksum = ip_csum_fold (sum0); - } - - /* Destination is behind the same NAT, use internal address and port */ - if (new_dst_addr0) - { - old_dst_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_dst_addr0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - ip0->checksum = ip_csum_fold (sum0); - } - } - -} - -static inline u32 icmp_in2out_slow_path (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - u32 rx_fib_index0, - vlib_node_runtime_t * node, - u32 next0, - f64 now, - u32 thread_index, - snat_session_t ** p_s0) -{ - next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, thread_index, p_s0, 0); - snat_session_t * s0 = *p_s0; - if (PREDICT_TRUE(next0 != SNAT_IN2OUT_NEXT_DROP && s0)) - { - /* Hairpinning */ - if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == 0) - snat_icmp_hairpinning(sm, b0, ip0, icmp0); - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); - /* Per-user LRU list maintenance for dynamic translations */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - } - return next0; -} -static inline void -snat_hairpinning_unknown_proto (snat_main_t *sm, - vlib_buffer_t * b, - ip4_header_t * ip) -{ - u32 old_addr, new_addr = 0, ti = 0; - clib_bihash_kv_8_8_t kv, value; - clib_bihash_kv_16_8_t s_kv, s_value; - snat_unk_proto_ses_key_t key; - snat_session_key_t m_key; - snat_worker_key_t w_key; - snat_static_mapping_t *m; - ip_csum_t sum; - snat_session_t *s; - - old_addr = ip->dst_address.as_u32; - key.l_addr.as_u32 = ip->dst_address.as_u32; - key.r_addr.as_u32 = ip->src_address.as_u32; - key.fib_index = sm->outside_fib_index; - key.proto = ip->protocol; - key.rsvd[0] = key.rsvd[1] = key.rsvd[2] = 0; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_search_16_8 (&sm->out2in_unk_proto, &s_kv, &s_value)) - { - m_key.addr = ip->dst_address; - m_key.fib_index = sm->outside_fib_index; - m_key.port = 0; - m_key.protocol = 0; - kv.key = m_key.as_u64; - if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) - return; - - m = pool_elt_at_index (sm->static_mappings, value.value); - if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer(b)->sw_if_index[VLIB_TX] = m->fib_index; - new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32; - } - else - { - if (sm->num_workers > 1) - { - w_key.addr = ip->dst_address; - w_key.port = 0; - w_key.fib_index = sm->outside_fib_index; - kv.key = w_key.as_u64; - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv, &value)) - return; - else - ti = value.value; - } - else - ti = sm->num_workers; - - s = pool_elt_at_index (sm->per_thread_data[ti].sessions, s_value.value); - if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index; - new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32; - } - sum = ip->checksum; - sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); - ip->checksum = ip_csum_fold (sum); -} - -static void -snat_in2out_unknown_proto (snat_main_t *sm, - vlib_buffer_t * b, - ip4_header_t * ip, - u32 rx_fib_index, - u32 thread_index, - f64 now, - vlib_main_t * vm) -{ - clib_bihash_kv_8_8_t kv, value; - clib_bihash_kv_16_8_t s_kv, s_value; - snat_static_mapping_t *m; - snat_session_key_t m_key; - u32 old_addr, new_addr = 0; - ip_csum_t sum; - snat_user_key_t u_key; - snat_user_t *u; - dlist_elt_t *head, *elt, *oldest; - snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - u32 elt_index, head_index, ses_index, oldest_index; - snat_session_t * s; - snat_unk_proto_ses_key_t key; - u32 address_index = ~0; - int i; - u8 is_sm = 0; - - old_addr = ip->src_address.as_u32; - - key.l_addr = ip->src_address; - key.r_addr = ip->dst_address; - key.fib_index = rx_fib_index; - key.proto = ip->protocol; - key.rsvd[0] = key.rsvd[1] = key.rsvd[2] = 0; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - - if (!clib_bihash_search_16_8 (&sm->in2out_unk_proto, &s_kv, &s_value)) - { - s = pool_elt_at_index (tsm->sessions, s_value.value); - new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; - } - else - { - u_key.addr = ip->src_address; - u_key.fib_index = rx_fib_index; - kv.key = u_key.as_u64; - - /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) - { - /* no, make a new one */ - pool_get (tsm->users, u); - memset (u, 0, sizeof (*u)); - u->addr = ip->src_address; - u->fib_index = rx_fib_index; - - pool_get (tsm->list_pool, head); - u->sessions_per_user_list_head_index = head - tsm->list_pool; - - clib_dlist_init (tsm->list_pool, - u->sessions_per_user_list_head_index); - - kv.value = u - tsm->users; - - /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 1); - } - else - { - u = pool_elt_at_index (tsm->users, value.value); - } - - m_key.addr = ip->src_address; - m_key.port = 0; - m_key.protocol = 0; - m_key.fib_index = rx_fib_index; - kv.key = m_key.as_u64; - - /* Try to find static mapping first */ - if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value)) - { - m = pool_elt_at_index (sm->static_mappings, value.value); - new_addr = ip->src_address.as_u32 = m->external_addr.as_u32; - is_sm = 1; - goto create_ses; - } - /* Fallback to 3-tuple key */ - else - { - /* Choose same out address as for TCP/UDP session to same destination */ - if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) - { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tsm->list_pool, head_index); - elt_index = head->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - while (ses_index != ~0) - { - s = pool_elt_at_index (tsm->sessions, ses_index); - elt_index = elt->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - - if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32) - { - new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; - address_index = s->outside_address_index; - - key.fib_index = sm->outside_fib_index; - key.l_addr.as_u32 = new_addr; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_search_16_8 (&sm->out2in_unk_proto, &s_kv, &s_value)) - break; - - goto create_ses; - } - } - } - key.fib_index = sm->outside_fib_index; - for (i = 0; i < vec_len (sm->addresses); i++) - { - key.l_addr.as_u32 = sm->addresses[i].addr.as_u32; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_search_16_8 (&sm->out2in_unk_proto, &s_kv, &s_value)) - { - new_addr = ip->src_address.as_u32 = key.l_addr.as_u32; - address_index = i; - goto create_ses; - } - } - return; - } - -create_ses: - /* Over quota? Recycle the least recently used dynamic translation */ - if (u->nsessions >= sm->max_translations_per_user && !is_sm) - { - /* Remove the oldest dynamic translation */ - do { - oldest_index = clib_dlist_remove_head ( - tsm->list_pool, u->sessions_per_user_list_head_index); - - ASSERT (oldest_index != ~0); - - /* add it back to the end of the LRU list */ - clib_dlist_addtail (tsm->list_pool, - u->sessions_per_user_list_head_index, - oldest_index); - /* Get the list element */ - oldest = pool_elt_at_index (tsm->list_pool, oldest_index); - - /* Get the session index from the list element */ - ses_index = oldest->value; - - /* Get the session */ - s = pool_elt_at_index (tsm->sessions, ses_index); - } while (snat_is_session_static (s)); - - if (snat_is_unk_proto_session (s)) - { - /* Remove from lookup tables */ - key.l_addr = s->in2out.addr; - key.r_addr = s->ext_host_addr; - key.fib_index = s->in2out.fib_index; - key.proto = s->in2out.port; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_unk_proto, &s_kv, 0)) - clib_warning ("in2out key del failed"); - - key.l_addr = s->out2in.addr; - key.fib_index = s->out2in.fib_index; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->out2in_unk_proto, &s_kv, 0)) - clib_warning ("out2in key del failed"); - } - else - { - /* log NAT event */ - snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32, - s->out2in.addr.as_u32, - s->in2out.protocol, - s->in2out.port, - s->out2in.port, - s->in2out.fib_index); - - snat_free_outside_address_and_port (sm, &s->out2in, - s->outside_address_index); - - /* Remove in2out, out2in keys */ - kv.key = s->in2out.as_u64; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0)) - clib_warning ("in2out key del failed"); - kv.key = s->out2in.as_u64; - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0)) - clib_warning ("out2in key del failed"); - } - } - else - { - /* Create a new session */ - pool_get (tsm->sessions, s); - memset (s, 0, sizeof (*s)); - - /* Create list elts */ - pool_get (tsm->list_pool, elt); - clib_dlist_init (tsm->list_pool, elt - tsm->list_pool); - elt->value = s - tsm->sessions; - s->per_user_index = elt - tsm->list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); - } - - s->ext_host_addr.as_u32 = ip->dst_address.as_u32; - s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; - s->outside_address_index = address_index; - s->out2in.addr.as_u32 = new_addr; - s->out2in.fib_index = sm->outside_fib_index; - s->in2out.addr.as_u32 = old_addr; - s->in2out.fib_index = rx_fib_index; - s->in2out.port = s->out2in.port = ip->protocol; - if (is_sm) - { - u->nstaticsessions++; - s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - } - else - { - u->nsessions++; - } - - /* Add to lookup tables */ - key.l_addr.as_u32 = old_addr; - key.r_addr = ip->dst_address; - key.proto = ip->protocol; - key.fib_index = rx_fib_index; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - s_kv.value = s - tsm->sessions; - if (clib_bihash_add_del_16_8 (&sm->in2out_unk_proto, &s_kv, 1)) - clib_warning ("in2out key add failed"); - - key.l_addr.as_u32 = new_addr; - key.fib_index = sm->outside_fib_index; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->out2in_unk_proto, &s_kv, 1)) - clib_warning ("out2in key add failed"); - } - - /* Update IP checksum */ - sum = ip->checksum; - sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address); - ip->checksum = ip_csum_fold (sum); - - /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); - /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); - - /* Hairpinning */ - if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0) - snat_hairpinning_unknown_proto(sm, b, ip); - - if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer(b)->sw_if_index[VLIB_TX] = sm->outside_fib_index; -} - -static inline uword -snat_in2out_node_fn_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, int is_slow_path, - int is_output_feature) -{ - u32 n_left_from, * from, * to_next; - snat_in2out_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - f64 now = vlib_time_now (vm); - u32 stats_node_index; - u32 thread_index = vlib_get_thread_index (); - - stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index : - snat_in2out_node.index; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - u32 next0, next1; - u32 sw_if_index0, sw_if_index1; - ip4_header_t * ip0, * ip1; - ip_csum_t sum0, sum1; - u32 new_addr0, old_addr0, new_addr1, old_addr1; - u16 old_port0, new_port0, old_port1, new_port1; - udp_header_t * udp0, * udp1; - tcp_header_t * tcp0, * tcp1; - icmp46_header_t * icmp0, * icmp1; - snat_session_key_t key0, key1; - u32 rx_fib_index0, rx_fib_index1; - u32 proto0, proto1; - snat_session_t * s0 = 0, * s1 = 0; - clib_bihash_kv_8_8_t kv0, value0, kv1, value1; - u32 iph_offset0 = 0, iph_offset1 = 0; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - if (is_output_feature) - iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length; - - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + - iph_offset0); - - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP; - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace00; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - /* Next configured feature, probably ip4-lookup */ - if (is_slow_path) - { - if (PREDICT_FALSE (proto0 == ~0)) - { - snat_in2out_unknown_proto (sm, b0, ip0, rx_fib_index0, - thread_index, now, vm); - goto trace00; - } - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_in2out_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, - node, next0, now, thread_index, &s0); - goto trace00; - } - } - else - { - if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace00; - } - } - - key0.addr = ip0->src_address; - key0.port = udp0->src_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (PREDICT_FALSE (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0) != 0)) - { - if (is_slow_path) - { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, - ip0, proto0, rx_fib_index0)) && !is_output_feature) - goto trace00; - - next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, thread_index); - if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) - goto trace00; - } - else - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace00; - } - } - else - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); - - old_addr0 = ip0->src_address.as_u32; - ip0->src_address = s0->out2in.addr; - new_addr0 = ip0->src_address.as_u32; - if (!is_output_feature) - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->src_port; - tcp0->src_port = s0->out2in.port; - new_port0 = tcp0->src_port; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->src_port; - udp0->src_port = s0->out2in.port; - udp0->checksum = 0; - } - - /* Hairpinning */ - if (!is_output_feature) - snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - trace00: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->is_slow_path = is_slow_path; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[thread_index].sessions; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - if (is_output_feature) - iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length; - - ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) + - iph_offset1); - - udp1 = ip4_next_header (ip1); - tcp1 = (tcp_header_t *) udp1; - icmp1 = (icmp46_header_t *) udp1; - - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index1); - - if (PREDICT_FALSE(ip1->ttl == 1)) - { - vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace01; - } - - proto1 = ip_proto_to_snat_proto (ip1->protocol); - - /* Next configured feature, probably ip4-lookup */ - if (is_slow_path) - { - if (PREDICT_FALSE (proto1 == ~0)) - { - snat_in2out_unknown_proto (sm, b1, ip1, rx_fib_index1, - thread_index, now, vm); - goto trace01; - } - - if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP)) - { - next1 = icmp_in2out_slow_path - (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, - next1, now, thread_index, &s1); - goto trace01; - } - } - else - { - if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP)) - { - next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace01; - } - } - - key1.addr = ip1->src_address; - key1.port = udp1->src_port; - key1.protocol = proto1; - key1.fib_index = rx_fib_index1; - - kv1.key = key1.as_u64; - - if (PREDICT_FALSE(clib_bihash_search_8_8 (&sm->in2out, &kv1, &value1) != 0)) - { - if (is_slow_path) - { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index1, - ip1, proto1, rx_fib_index1)) && !is_output_feature) - goto trace01; - - next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1, - &s1, node, next1, thread_index); - if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP)) - goto trace01; - } - else - { - next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace01; - } - } - else - s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value1.value); - - old_addr1 = ip1->src_address.as_u32; - ip1->src_address = s1->out2in.addr; - new_addr1 = ip1->src_address.as_u32; - if (!is_output_feature) - vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index; - - sum1 = ip1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - src_address /* changed member */); - ip1->checksum = ip_csum_fold (sum1); - - if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) - { - old_port1 = tcp1->src_port; - tcp1->src_port = s1->out2in.port; - new_port1 = tcp1->src_port; - - sum1 = tcp1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - dst_address /* changed member */); - sum1 = ip_csum_update (sum1, old_port1, new_port1, - ip4_header_t /* cheat */, - length /* changed member */); - tcp1->checksum = ip_csum_fold(sum1); - } - else - { - old_port1 = udp1->src_port; - udp1->src_port = s1->out2in.port; - udp1->checksum = 0; - } - - /* Hairpinning */ - if (!is_output_feature) - snat_hairpinning (sm, b1, ip1, udp1, tcp1, proto1); - - /* Accounting */ - s1->last_heard = now; - s1->total_pkts++; - s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s1)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s1->per_user_list_head_index, - s1->per_user_index); - } - trace01: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b1->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - t->next_index = next1; - t->session_index = ~0; - if (s1) - t->session_index = s1 - sm->per_thread_data[thread_index].sessions; - } - - pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP; - - /* verify speculative enqueues, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 old_port0, new_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0; - u32 rx_fib_index0; - u32 proto0; - snat_session_t * s0 = 0; - clib_bihash_kv_8_8_t kv0, value0; - u32 iph_offset0 = 0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - next0 = SNAT_IN2OUT_NEXT_LOOKUP; - - if (is_output_feature) - iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length; - - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + - iph_offset0); - - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace0; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - /* Next configured feature, probably ip4-lookup */ - if (is_slow_path) - { - if (PREDICT_FALSE (proto0 == ~0)) - { - snat_in2out_unknown_proto (sm, b0, ip0, rx_fib_index0, - thread_index, now, vm); - goto trace0; - } - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_in2out_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, thread_index, &s0); - goto trace0; - } - } - else - { - if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace0; - } - } - - key0.addr = ip0->src_address; - key0.port = udp0->src_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0)) - { - if (is_slow_path) - { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, - ip0, proto0, rx_fib_index0)) && !is_output_feature) - goto trace0; - - next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, thread_index); - - if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) - goto trace0; - } - else - { - next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; - goto trace0; - } - } - else - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); - - old_addr0 = ip0->src_address.as_u32; - ip0->src_address = s0->out2in.addr; - new_addr0 = ip0->src_address.as_u32; - if (!is_output_feature) - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->src_port; - tcp0->src_port = s0->out2in.port; - new_port0 = tcp0->src_port; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->src_port; - udp0->src_port = s0->out2in.port; - udp0->checksum = 0; - } - - /* Hairpinning */ - if (!is_output_feature) - snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - - trace0: - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->is_slow_path = is_slow_path; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[thread_index].sessions; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, stats_node_index, - SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -static uword -snat_in2out_fast_path_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, 0); -} - -VLIB_REGISTER_NODE (snat_in2out_node) = { - .function = snat_in2out_fast_path_fn, - .name = "snat-in2out", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", - [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_node, snat_in2out_fast_path_fn); - -static uword -snat_in2out_output_fast_path_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, 1); -} - -VLIB_REGISTER_NODE (snat_in2out_output_node) = { - .function = snat_in2out_output_fast_path_fn, - .name = "snat-in2out-output", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-output-slowpath", - [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_node, - snat_in2out_output_fast_path_fn); - -static uword -snat_in2out_slow_path_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, 0); -} - -VLIB_REGISTER_NODE (snat_in2out_slowpath_node) = { - .function = snat_in2out_slow_path_fn, - .name = "snat-in2out-slowpath", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", - [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_slowpath_node, - snat_in2out_slow_path_fn); - -static uword -snat_in2out_output_slow_path_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, 1); -} - -VLIB_REGISTER_NODE (snat_in2out_output_slowpath_node) = { - .function = snat_in2out_output_slow_path_fn, - .name = "snat-in2out-output-slowpath", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-output-slowpath", - [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_slowpath_node, - snat_in2out_output_slow_path_fn); - -/**************************/ -/*** deterministic mode ***/ -/**************************/ -static uword -snat_det_in2out_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_in2out_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - u32 now = (u32) vlib_time_now (vm); - u32 thread_index = vlib_get_thread_index (); - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - u32 next0, next1; - u32 sw_if_index0, sw_if_index1; - ip4_header_t * ip0, * ip1; - ip_csum_t sum0, sum1; - ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1; - u16 old_port0, new_port0, lo_port0, i0; - u16 old_port1, new_port1, lo_port1, i1; - udp_header_t * udp0, * udp1; - tcp_header_t * tcp0, * tcp1; - u32 proto0, proto1; - snat_det_out_key_t key0, key1; - snat_det_map_t * dm0, * dm1; - snat_det_session_t * ses0 = 0, * ses1 = 0; - u32 rx_fib_index0, rx_fib_index1; - icmp46_header_t * icmp0, * icmp1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - next0 = SNAT_IN2OUT_NEXT_LOOKUP; - next1 = SNAT_IN2OUT_NEXT_LOOKUP; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace0; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) - { - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - icmp0 = (icmp46_header_t *) udp0; - - next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, thread_index, - &ses0, &dm0); - goto trace0; - } - - dm0 = snat_det_map_by_user(sm, &ip0->src_address); - if (PREDICT_FALSE(!dm0)) - { - clib_warning("no match for internal host %U", - format_ip4_address, &ip0->src_address); - next0 = SNAT_IN2OUT_NEXT_DROP; - b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - goto trace0; - } - - snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0); - - key0.ext_host_addr = ip0->dst_address; - key0.ext_host_port = tcp0->dst; - - ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src, key0); - if (PREDICT_FALSE(!ses0)) - { - for (i0 = 0; i0 < dm0->ports_per_host; i0++) - { - key0.out_port = clib_host_to_net_u16 (lo_port0 + - ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host)); - - if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64)) - continue; - - ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0); - break; - } - if (PREDICT_FALSE(!ses0)) - { - /* too many sessions for user, send ICMP error packet */ - - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_destination_unreachable, - ICMP4_destination_unreachable_destination_unreachable_host, - 0); - next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace0; - } - } - - new_port0 = ses0->out.out_port; - - old_addr0.as_u32 = ip0->src_address.as_u32; - ip0->src_address.as_u32 = new_addr0.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - if (tcp0->flags & TCP_FLAG_SYN) - ses0->state = SNAT_SESSION_TCP_SYN_SENT; - else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT) - ses0->state = SNAT_SESSION_TCP_ESTABLISHED; - else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED) - ses0->state = SNAT_SESSION_TCP_FIN_WAIT; - else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT) - snat_det_ses_close(dm0, ses0); - else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT) - ses0->state = SNAT_SESSION_TCP_LAST_ACK; - else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN) - ses0->state = SNAT_SESSION_TCP_ESTABLISHED; - - old_port0 = tcp0->src; - tcp0->src = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - ses0->state = SNAT_SESSION_UDP_ACTIVE; - old_port0 = udp0->src_port; - udp0->src_port = new_port0; - udp0->checksum = 0; - } - - switch(ses0->state) - { - case SNAT_SESSION_UDP_ACTIVE: - ses0->expire = now + sm->udp_timeout; - break; - case SNAT_SESSION_TCP_SYN_SENT: - case SNAT_SESSION_TCP_FIN_WAIT: - case SNAT_SESSION_TCP_CLOSE_WAIT: - case SNAT_SESSION_TCP_LAST_ACK: - ses0->expire = now + sm->tcp_transitory_timeout; - break; - case SNAT_SESSION_TCP_ESTABLISHED: - ses0->expire = now + sm->tcp_established_timeout; - break; - } - - trace0: - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->is_slow_path = 0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (ses0) - t->session_index = ses0 - dm0->sessions; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - ip1 = vlib_buffer_get_current (b1); - udp1 = ip4_next_header (ip1); - tcp1 = (tcp_header_t *) udp1; - - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - - if (PREDICT_FALSE(ip1->ttl == 1)) - { - vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace1; - } - - proto1 = ip_proto_to_snat_proto (ip1->protocol); - - if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP)) - { - rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1); - icmp1 = (icmp46_header_t *) udp1; - - next1 = icmp_in2out(sm, b1, ip1, icmp1, sw_if_index1, - rx_fib_index1, node, next1, thread_index, - &ses1, &dm1); - goto trace1; - } - - dm1 = snat_det_map_by_user(sm, &ip1->src_address); - if (PREDICT_FALSE(!dm1)) - { - clib_warning("no match for internal host %U", - format_ip4_address, &ip0->src_address); - next1 = SNAT_IN2OUT_NEXT_DROP; - b1->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - goto trace1; - } - - snat_det_forward(dm1, &ip1->src_address, &new_addr1, &lo_port1); - - key1.ext_host_addr = ip1->dst_address; - key1.ext_host_port = tcp1->dst; - - ses1 = snat_det_find_ses_by_in(dm1, &ip1->src_address, tcp1->src, key1); - if (PREDICT_FALSE(!ses1)) - { - for (i1 = 0; i1 < dm1->ports_per_host; i1++) - { - key1.out_port = clib_host_to_net_u16 (lo_port1 + - ((i1 + clib_net_to_host_u16 (tcp1->src)) % dm1->ports_per_host)); - - if (snat_det_get_ses_by_out (dm1, &ip1->src_address, key1.as_u64)) - continue; - - ses1 = snat_det_ses_create(dm1, &ip1->src_address, tcp1->src, &key1); - break; - } - if (PREDICT_FALSE(!ses1)) - { - /* too many sessions for user, send ICMP error packet */ - - vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b1, ICMP4_destination_unreachable, - ICMP4_destination_unreachable_destination_unreachable_host, - 0); - next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace1; - } - } - - new_port1 = ses1->out.out_port; - - old_addr1.as_u32 = ip1->src_address.as_u32; - ip1->src_address.as_u32 = new_addr1.as_u32; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index; - - sum1 = ip1->checksum; - sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32, - ip4_header_t, - src_address /* changed member */); - ip1->checksum = ip_csum_fold (sum1); - - if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) - { - if (tcp1->flags & TCP_FLAG_SYN) - ses1->state = SNAT_SESSION_TCP_SYN_SENT; - else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_SYN_SENT) - ses1->state = SNAT_SESSION_TCP_ESTABLISHED; - else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED) - ses1->state = SNAT_SESSION_TCP_FIN_WAIT; - else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_FIN_WAIT) - snat_det_ses_close(dm1, ses1); - else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT) - ses1->state = SNAT_SESSION_TCP_LAST_ACK; - else if (tcp1->flags == 0 && ses1->state == SNAT_SESSION_UNKNOWN) - ses1->state = SNAT_SESSION_TCP_ESTABLISHED; - - old_port1 = tcp1->src; - tcp1->src = new_port1; - - sum1 = tcp1->checksum; - sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32, - ip4_header_t, - dst_address /* changed member */); - sum1 = ip_csum_update (sum1, old_port1, new_port1, - ip4_header_t /* cheat */, - length /* changed member */); - tcp1->checksum = ip_csum_fold(sum1); - } - else - { - ses1->state = SNAT_SESSION_UDP_ACTIVE; - old_port1 = udp1->src_port; - udp1->src_port = new_port1; - udp1->checksum = 0; - } - - switch(ses1->state) - { - case SNAT_SESSION_UDP_ACTIVE: - ses1->expire = now + sm->udp_timeout; - break; - case SNAT_SESSION_TCP_SYN_SENT: - case SNAT_SESSION_TCP_FIN_WAIT: - case SNAT_SESSION_TCP_CLOSE_WAIT: - case SNAT_SESSION_TCP_LAST_ACK: - ses1->expire = now + sm->tcp_transitory_timeout; - break; - case SNAT_SESSION_TCP_ESTABLISHED: - ses1->expire = now + sm->tcp_established_timeout; - break; - } - - trace1: - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b1->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->is_slow_path = 0; - t->sw_if_index = sw_if_index1; - t->next_index = next1; - t->session_index = ~0; - if (ses1) - t->session_index = ses1 - dm1->sessions; - } - - pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP; - - /* verify speculative enqueues, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - ip4_address_t new_addr0, old_addr0; - u16 old_port0, new_port0, lo_port0, i0; - udp_header_t * udp0; - tcp_header_t * tcp0; - u32 proto0; - snat_det_out_key_t key0; - snat_det_map_t * dm0; - snat_det_session_t * ses0 = 0; - u32 rx_fib_index0; - icmp46_header_t * icmp0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - next0 = SNAT_IN2OUT_NEXT_LOOKUP; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace00; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) - { - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - icmp0 = (icmp46_header_t *) udp0; - - next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, thread_index, - &ses0, &dm0); - goto trace00; - } - - dm0 = snat_det_map_by_user(sm, &ip0->src_address); - if (PREDICT_FALSE(!dm0)) - { - clib_warning("no match for internal host %U", - format_ip4_address, &ip0->src_address); - next0 = SNAT_IN2OUT_NEXT_DROP; - b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - goto trace00; - } - - snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0); - - key0.ext_host_addr = ip0->dst_address; - key0.ext_host_port = tcp0->dst; - - ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src, key0); - if (PREDICT_FALSE(!ses0)) - { - for (i0 = 0; i0 < dm0->ports_per_host; i0++) - { - key0.out_port = clib_host_to_net_u16 (lo_port0 + - ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host)); - - if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64)) - continue; - - ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0); - break; - } - if (PREDICT_FALSE(!ses0)) - { - /* too many sessions for user, send ICMP error packet */ - - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_destination_unreachable, - ICMP4_destination_unreachable_destination_unreachable_host, - 0); - next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace00; - } - } - - new_port0 = ses0->out.out_port; - - old_addr0.as_u32 = ip0->src_address.as_u32; - ip0->src_address.as_u32 = new_addr0.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - if (tcp0->flags & TCP_FLAG_SYN) - ses0->state = SNAT_SESSION_TCP_SYN_SENT; - else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT) - ses0->state = SNAT_SESSION_TCP_ESTABLISHED; - else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED) - ses0->state = SNAT_SESSION_TCP_FIN_WAIT; - else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT) - snat_det_ses_close(dm0, ses0); - else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT) - ses0->state = SNAT_SESSION_TCP_LAST_ACK; - else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN) - ses0->state = SNAT_SESSION_TCP_ESTABLISHED; - - old_port0 = tcp0->src; - tcp0->src = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - ses0->state = SNAT_SESSION_UDP_ACTIVE; - old_port0 = udp0->src_port; - udp0->src_port = new_port0; - udp0->checksum = 0; - } - - switch(ses0->state) - { - case SNAT_SESSION_UDP_ACTIVE: - ses0->expire = now + sm->udp_timeout; - break; - case SNAT_SESSION_TCP_SYN_SENT: - case SNAT_SESSION_TCP_FIN_WAIT: - case SNAT_SESSION_TCP_CLOSE_WAIT: - case SNAT_SESSION_TCP_LAST_ACK: - ses0->expire = now + sm->tcp_transitory_timeout; - break; - case SNAT_SESSION_TCP_ESTABLISHED: - ses0->expire = now + sm->tcp_established_timeout; - break; - } - - trace00: - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->is_slow_path = 0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (ses0) - t->session_index = ses0 - dm0->sessions; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, snat_det_in2out_node.index, - SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_det_in2out_node) = { - .function = snat_det_in2out_node_fn, - .name = "snat-det-in2out", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = 3, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_det_in2out_node, snat_det_in2out_node_fn); - -/** - * Get address and port values to be used for packet SNAT translation - * and create session if needed - * - * @param[in,out] sm SNAT main - * @param[in,out] node SNAT node runtime - * @param[in] thread_index thread index - * @param[in,out] b0 buffer containing packet to be translated - * @param[out] p_proto protocol used for matching - * @param[out] p_value address and port after NAT translation - * @param[out] p_dont_translate if packet should not be translated - * @param d optional parameter - * @param e optional parameter - */ -u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e) -{ - ip4_header_t *ip0; - icmp46_header_t *icmp0; - u32 sw_if_index0; - u32 rx_fib_index0; - u8 protocol; - snat_det_out_key_t key0; - u8 dont_translate = 0; - u32 next0 = ~0; - icmp_echo_header_t *echo0, *inner_echo0 = 0; - ip4_header_t *inner_ip0; - void *l4_header = 0; - icmp46_header_t *inner_icmp0; - snat_det_map_t * dm0 = 0; - ip4_address_t new_addr0; - u16 lo_port0, i0; - snat_det_session_t * ses0 = 0; - ip4_address_t in_addr; - u16 in_port; - - ip0 = vlib_buffer_get_current (b0); - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - echo0 = (icmp_echo_header_t *)(icmp0+1); - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); - - if (!icmp_is_error_message (icmp0)) - { - protocol = SNAT_PROTOCOL_ICMP; - in_addr = ip0->src_address; - in_port = echo0->identifier; - } - else - { - inner_ip0 = (ip4_header_t *)(echo0+1); - l4_header = ip4_next_header (inner_ip0); - protocol = ip_proto_to_snat_proto (inner_ip0->protocol); - in_addr = inner_ip0->dst_address; - switch (protocol) - { - case SNAT_PROTOCOL_ICMP: - inner_icmp0 = (icmp46_header_t*)l4_header; - inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); - in_port = inner_echo0->identifier; - break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - in_port = ((tcp_udp_header_t*)l4_header)->dst_port; - break; - default: - b0->error = node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - } - - dm0 = snat_det_map_by_user(sm, &in_addr); - if (PREDICT_FALSE(!dm0)) - { - clib_warning("no match for internal host %U", - format_ip4_address, &in_addr); - if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0, - IP_PROTOCOL_ICMP, rx_fib_index0))) - { - dont_translate = 1; - goto out; - } - next0 = SNAT_IN2OUT_NEXT_DROP; - b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - goto out; - } - - snat_det_forward(dm0, &in_addr, &new_addr0, &lo_port0); - - key0.ext_host_addr = ip0->dst_address; - key0.ext_host_port = 0; - - ses0 = snat_det_find_ses_by_in(dm0, &in_addr, in_port, key0); - if (PREDICT_FALSE(!ses0)) - { - if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0, - IP_PROTOCOL_ICMP, rx_fib_index0))) - { - dont_translate = 1; - goto out; - } - if (icmp0->type != ICMP4_echo_request) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - for (i0 = 0; i0 < dm0->ports_per_host; i0++) - { - key0.out_port = clib_host_to_net_u16 (lo_port0 + - ((i0 + clib_net_to_host_u16 (echo0->identifier)) % dm0->ports_per_host)); - - if (snat_det_get_ses_by_out (dm0, &in_addr, key0.as_u64)) - continue; - - ses0 = snat_det_ses_create(dm0, &in_addr, echo0->identifier, &key0); - break; - } - if (PREDICT_FALSE(!ses0)) - { - next0 = SNAT_IN2OUT_NEXT_DROP; - b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; - goto out; - } - } - - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request && - !icmp_is_error_message (icmp0))) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_IN2OUT_NEXT_DROP; - goto out; - } - - u32 now = (u32) vlib_time_now (sm->vlib_main); - - ses0->state = SNAT_SESSION_ICMP_ACTIVE; - ses0->expire = now + sm->icmp_timeout; - -out: - *p_proto = protocol; - if (ses0) - { - p_value->addr = new_addr0; - p_value->fib_index = sm->outside_fib_index; - p_value->port = ses0->out.out_port; - } - *p_dont_translate = dont_translate; - if (d) - *(snat_det_session_t**)d = ses0; - if (e) - *(snat_det_map_t**)e = dm0; - return next0; -} - -/**********************/ -/*** worker handoff ***/ -/**********************/ -static inline uword -snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, - u8 is_output) -{ - snat_main_t *sm = &snat_main; - vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 n_left_from, *from, *to_next = 0; - static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; - static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index - = 0; - vlib_frame_queue_elt_t *hf = 0; - vlib_frame_t *f = 0; - int i; - u32 n_left_to_next_worker = 0, *to_next_worker = 0; - u32 next_worker_index = 0; - u32 current_worker_index = ~0; - u32 thread_index = vlib_get_thread_index (); - u32 fq_index; - u32 to_node_index; - - ASSERT (vec_len (sm->workers)); - - if (is_output) - { - fq_index = sm->fq_in2out_output_index; - to_node_index = sm->in2out_output_node_index; - } - else - { - fq_index = sm->fq_in2out_index; - to_node_index = sm->in2out_node_index; - } - - if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0)) - { - vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); - - vec_validate_init_empty (congested_handoff_queue_by_worker_index, - sm->first_worker_index + sm->num_workers - 1, - (vlib_frame_queue_t *) (~0)); - } - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 sw_if_index0; - u32 rx_fib_index0; - ip4_header_t * ip0; - u8 do_handoff; - - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - ip0 = vlib_buffer_get_current (b0); - - next_worker_index = sm->worker_in2out_cb(ip0, rx_fib_index0); - - if (PREDICT_FALSE (next_worker_index != thread_index)) - { - do_handoff = 1; - - if (next_worker_index != current_worker_index) - { - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - hf = vlib_get_worker_handoff_queue_elt (fq_index, - next_worker_index, - handoff_queue_elt_by_worker_index); - - n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors; - to_next_worker = &hf->buffer_index[hf->n_vectors]; - current_worker_index = next_worker_index; - } - - /* enqueue to correct worker thread */ - to_next_worker[0] = bi0; - to_next_worker++; - n_left_to_next_worker--; - - if (n_left_to_next_worker == 0) - { - hf->n_vectors = VLIB_FRAME_SIZE; - vlib_put_frame_queue_elt (hf); - current_worker_index = ~0; - handoff_queue_elt_by_worker_index[next_worker_index] = 0; - hf = 0; - } - } - else - { - do_handoff = 0; - /* if this is 1st frame */ - if (!f) - { - f = vlib_get_frame_to_node (vm, to_node_index); - to_next = vlib_frame_vector_args (f); - } - - to_next[0] = bi0; - to_next += 1; - f->n_vectors++; - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_worker_handoff_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_worker_index = next_worker_index; - t->do_handoff = do_handoff; - } - } - - if (f) - vlib_put_frame_to_node (vm, to_node_index, f); - - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - /* Ship frames to the worker nodes */ - for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++) - { - if (handoff_queue_elt_by_worker_index[i]) - { - hf = handoff_queue_elt_by_worker_index[i]; - /* - * It works better to let the handoff node - * rate-adapt, always ship the handoff queue element. - */ - if (1 || hf->n_vectors == hf->last_n_vectors) - { - vlib_put_frame_queue_elt (hf); - handoff_queue_elt_by_worker_index[i] = 0; - } - else - hf->last_n_vectors = hf->n_vectors; - } - congested_handoff_queue_by_worker_index[i] = - (vlib_frame_queue_t *) (~0); - } - hf = 0; - current_worker_index = ~0; - return frame->n_vectors; -} - -static uword -snat_in2out_worker_handoff_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_worker_handoff_fn_inline (vm, node, frame, 0); -} - -VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = { - .function = snat_in2out_worker_handoff_fn, - .name = "snat-in2out-worker-handoff", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_worker_handoff_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_worker_handoff_node, - snat_in2out_worker_handoff_fn); - -static uword -snat_in2out_output_worker_handoff_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return snat_in2out_worker_handoff_fn_inline (vm, node, frame, 1); -} - -VLIB_REGISTER_NODE (snat_in2out_output_worker_handoff_node) = { - .function = snat_in2out_output_worker_handoff_fn, - .name = "snat-in2out-output-worker-handoff", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_worker_handoff_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_worker_handoff_node, - snat_in2out_output_worker_handoff_fn); - -static_always_inline int -is_hairpinning (snat_main_t *sm, ip4_address_t * dst_addr) -{ - snat_address_t * ap; - clib_bihash_kv_8_8_t kv, value; - snat_session_key_t m_key; - - vec_foreach (ap, sm->addresses) - { - if (ap->addr.as_u32 == dst_addr->as_u32) - return 1; - } - - m_key.addr.as_u32 = dst_addr->as_u32; - m_key.fib_index = sm->outside_fib_index; - m_key.port = 0; - m_key.protocol = 0; - kv.key = m_key.as_u64; - if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) - return 1; - - return 0; -} - -static uword -snat_hairpin_dst_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_in2out_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; - ip4_header_t * ip0; - u32 proto0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - next0 = SNAT_IN2OUT_NEXT_LOOKUP; - ip0 = vlib_buffer_get_current (b0); - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - vnet_buffer (b0)->snat.flags = 0; - if (PREDICT_FALSE (is_hairpinning (sm, &ip0->dst_address))) - { - if (proto0 == SNAT_PROTOCOL_TCP || proto0 == SNAT_PROTOCOL_UDP) - { - udp_header_t * udp0 = ip4_next_header (ip0); - tcp_header_t * tcp0 = (tcp_header_t *) udp0; - - snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); - } - else if (proto0 == SNAT_PROTOCOL_ICMP) - { - icmp46_header_t * icmp0 = ip4_next_header (ip0); - - snat_icmp_hairpinning (sm, b0, ip0, icmp0); - } - else - { - snat_hairpinning_unknown_proto (sm, b0, ip0); - } - - vnet_buffer (b0)->snat.flags = SNAT_FLAG_HAIRPINNING; - clib_warning("is hairpinning"); - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, snat_hairpin_dst_node.index, - SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_hairpin_dst_node) = { - .function = snat_hairpin_dst_fn, - .name = "snat-hairpin-dst", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - .n_next_nodes = 2, - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_hairpin_dst_node, - snat_hairpin_dst_fn); - -static uword -snat_hairpin_src_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_in2out_next_t next_index; - u32 pkts_processed = 0; - snat_main_t *sm = &snat_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - next0 = SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT; - - if (PREDICT_FALSE ((vnet_buffer (b0)->snat.flags) & SNAT_FLAG_HAIRPINNING)) - { - if (PREDICT_TRUE (sm->num_workers > 1)) - next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH; - else - next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, snat_hairpin_src_node.index, - SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_hairpin_src_node) = { - .function = snat_hairpin_src_fn, - .name = "snat-hairpin-src", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - .n_next_nodes = SNAT_HAIRPIN_SRC_N_NEXT, - .next_nodes = { - [SNAT_HAIRPIN_SRC_NEXT_DROP] = "error-drop", - [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT] = "snat-in2out-output", - [SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT] = "interface-output", - [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH] = "snat-in2out-output-worker-handoff", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_hairpin_src_node, - snat_hairpin_src_fn); - -static uword -snat_in2out_fast_static_map_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_in2out_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - u32 stats_node_index; - - stats_node_index = snat_in2out_fast_node.index; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 old_port0, new_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0, sm0; - u32 proto0; - u32 rx_fib_index0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - next0 = SNAT_IN2OUT_NEXT_LOOKUP; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR; - goto trace0; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - goto trace0; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, ~0, 0, 0); - goto trace0; - } - - key0.addr = ip0->src_address; - key0.port = udp0->src_port; - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 0, 0)) - { - b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; - next0= SNAT_IN2OUT_NEXT_DROP; - goto trace0; - } - - new_addr0 = sm0.addr.as_u32; - new_port0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - old_addr0 = ip0->src_address.as_u32; - ip0->src_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE(new_port0 != udp0->dst_port)) - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->src_port; - tcp0->src_port = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->src_port; - udp0->src_port = new_port0; - udp0->checksum = 0; - } - } - else - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - } - - /* Hairpinning */ - snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0); - - trace0: - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - - pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, stats_node_index, - SNAT_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - - -VLIB_REGISTER_NODE (snat_in2out_fast_node) = { - .function = snat_in2out_fast_static_map_fn, - .name = "snat-in2out-fast", - .vector_size = sizeof (u32), - .format_trace = format_snat_in2out_fast_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_in2out_error_strings), - .error_strings = snat_in2out_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_IN2OUT_NEXT_DROP] = "error-drop", - [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath", - [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_fast_node, snat_in2out_fast_static_map_fn); diff --git a/src/plugins/snat/nat64.c b/src/plugins/snat/nat64.c deleted file mode 100644 index bd915b590d0..00000000000 --- a/src/plugins/snat/nat64.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief NAT64 implementation - */ - -#include <snat/nat64.h> -#include <snat/nat64_db.h> -#include <vnet/fib/ip4_fib.h> - - -nat64_main_t nat64_main; - -/* *INDENT-OFF* */ - -/* Hook up input features */ -VNET_FEATURE_INIT (nat64_in2out, static) = { - .arc_name = "ip6-unicast", - .node_name = "nat64-in2out", - .runs_before = VNET_FEATURES ("ip6-lookup"), -}; -VNET_FEATURE_INIT (nat64_out2in, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat64-out2in", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; - -static u8 well_known_prefix[] = { - 0x00, 0x64, 0xff, 0x9b, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -/* *INDENT-ON* */ - -clib_error_t * -nat64_init (vlib_main_t * vm) -{ - nat64_main_t *nm = &nat64_main; - clib_error_t *error = 0; - vlib_thread_main_t *tm = vlib_get_thread_main (); - - nm->is_disabled = 0; - - if (tm->n_vlib_mains > 1) - { - nm->is_disabled = 1; - goto error; - } - - if (nat64_db_init (&nm->db)) - { - error = clib_error_return (0, "NAT64 DB init failed"); - goto error; - } - - /* set session timeouts to default values */ - nm->udp_timeout = SNAT_UDP_TIMEOUT; - nm->icmp_timeout = SNAT_ICMP_TIMEOUT; - nm->tcp_trans_timeout = SNAT_TCP_TRANSITORY_TIMEOUT; - nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; - nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN; - -error: - return error; -} - -int -nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add) -{ - nat64_main_t *nm = &nat64_main; - snat_address_t *a = 0; - snat_interface_t *interface; - int i; - - /* Check if address already exists */ - for (i = 0; i < vec_len (nm->addr_pool); i++) - { - if (nm->addr_pool[i].addr.as_u32 == addr->as_u32) - { - a = nm->addr_pool + i; - break; - } - } - - if (is_add) - { - if (a) - return VNET_API_ERROR_VALUE_EXIST; - - vec_add2 (nm->addr_pool, a, 1); - a->addr = *addr; - a->fib_index = 0; - if (vrf_id != ~0) - a->fib_index = - fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id); -#define _(N, i, n, s) \ - clib_bitmap_alloc (a->busy_##n##_port_bitmap, 65535); - foreach_snat_protocol -#undef _ - } - else - { - if (!a) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - if (a->fib_index) - fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6); - -#define _(N, id, n, s) \ - clib_bitmap_free (a->busy_##n##_port_bitmap); - foreach_snat_protocol -#undef _ - /* Delete sessions using address */ - nat64_db_free_out_addr (&nm->db, &a->addr); - vec_del1 (nm->addr_pool, i); - } - - /* Add/del external address to FIB */ - /* *INDENT-OFF* */ - pool_foreach (interface, nm->interfaces, - ({ - if (interface->is_inside) - continue; - - snat_add_del_addr_to_fib (addr, 32, interface->sw_if_index, is_add); - break; - })); - /* *INDENT-ON* */ - - return 0; -} - -void -nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx) -{ - nat64_main_t *nm = &nat64_main; - snat_address_t *a = 0; - - /* *INDENT-OFF* */ - vec_foreach (a, nm->addr_pool) - { - if (fn (a, ctx)) - break; - }; - /* *INDENT-ON* */ -} - -int -nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add) -{ - nat64_main_t *nm = &nat64_main; - snat_interface_t *interface = 0, *i; - snat_address_t *ap; - const char *feature_name, *arc_name; - - /* Check if address already exists */ - /* *INDENT-OFF* */ - pool_foreach (i, nm->interfaces, - ({ - if (i->sw_if_index == sw_if_index) - { - interface = i; - break; - } - })); - /* *INDENT-ON* */ - - if (is_add) - { - if (interface) - return VNET_API_ERROR_VALUE_EXIST; - - pool_get (nm->interfaces, interface); - interface->sw_if_index = sw_if_index; - interface->is_inside = is_inside; - - } - else - { - if (!interface) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - pool_put (nm->interfaces, interface); - } - - if (!is_inside) - { - /* *INDENT-OFF* */ - vec_foreach (ap, nm->addr_pool) - snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, is_add); - /* *INDENT-ON* */ - } - - arc_name = is_inside ? "ip6-unicast" : "ip4-unicast"; - feature_name = is_inside ? "nat64-in2out" : "nat64-out2in"; - - return vnet_feature_enable_disable (arc_name, feature_name, sw_if_index, - is_add, 0, 0); -} - -void -nat64_interfaces_walk (nat64_interface_walk_fn_t fn, void *ctx) -{ - nat64_main_t *nm = &nat64_main; - snat_interface_t *i = 0; - - /* *INDENT-OFF* */ - pool_foreach (i, nm->interfaces, - ({ - if (fn (i, ctx)) - break; - })); - /* *INDENT-ON* */ -} - -int -nat64_alloc_out_addr_and_port (u32 fib_index, snat_protocol_t proto, - ip4_address_t * addr, u16 * port) -{ - nat64_main_t *nm = &nat64_main; - snat_main_t *sm = &snat_main; - int i; - snat_address_t *a, *ga = 0; - u32 portnum; - - for (i = 0; i < vec_len (nm->addr_pool); i++) - { - a = nm->addr_pool + i; - switch (proto) - { -#define _(N, j, n, s) \ - case SNAT_PROTOCOL_##N: \ - if (a->busy_##n##_ports < (65535-1024)) \ - { \ - if (a->fib_index == fib_index) \ - { \ - while (1) \ - { \ - portnum = random_u32 (&sm->random_seed); \ - portnum &= 0xFFFF; \ - if (portnum < 1024) \ - continue; \ - if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \ - portnum)) \ - continue; \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \ - portnum, 1); \ - a->busy_##n##_ports++; \ - *port = portnum; \ - addr->as_u32 = a->addr.as_u32; \ - return 0; \ - } \ - } \ - else if (a->fib_index == 0) \ - ga = a; \ - } \ - break; - foreach_snat_protocol -#undef _ - default: - clib_warning ("unknown protocol"); - return 1; - } - } - - if (ga) - { - switch (proto) - { -#define _(N, j, n, s) \ - case SNAT_PROTOCOL_##N: \ - while (1) \ - { \ - portnum = random_u32 (&sm->random_seed); \ - portnum &= 0xFFFF; \ - if (portnum < 1024) \ - continue; \ - if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \ - portnum)) \ - continue; \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \ - portnum, 1); \ - a->busy_##n##_ports++; \ - *port = portnum; \ - addr->as_u32 = a->addr.as_u32; \ - return 0; \ - } - break; - foreach_snat_protocol -#undef _ - default: - clib_warning ("unknown protocol"); - return 1; - } - } - - /* Totally out of translations to use... */ - //TODO: IPFix - return 1; -} - -void -nat64_free_out_addr_and_port (ip4_address_t * addr, u16 port, - snat_protocol_t proto) -{ - nat64_main_t *nm = &nat64_main; - int i; - snat_address_t *a; - - for (i = 0; i < vec_len (nm->addr_pool); i++) - { - a = nm->addr_pool + i; - if (addr->as_u32 != a->addr.as_u32) - continue; - switch (proto) - { -#define _(N, j, n, s) \ - case SNAT_PROTOCOL_##N: \ - ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \ - port) == 1); \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port, 0); \ - a->busy_##n##_ports--; \ - break; - foreach_snat_protocol -#undef _ - default: - clib_warning ("unknown protocol"); - return; - } - break; - } -} - -int -nat64_add_del_static_bib_entry (ip6_address_t * in_addr, - ip4_address_t * out_addr, u16 in_port, - u16 out_port, u8 proto, u32 vrf_id, u8 is_add) -{ - nat64_main_t *nm = &nat64_main; - nat64_db_bib_entry_t *bibe; - u32 fib_index = - fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id); - snat_protocol_t p = ip_proto_to_snat_proto (proto); - ip46_address_t addr; - int i; - snat_address_t *a; - - addr.as_u64[0] = in_addr->as_u64[0]; - addr.as_u64[1] = in_addr->as_u64[1]; - bibe = - nat64_db_bib_entry_find (&nm->db, &addr, clib_host_to_net_u16 (in_port), - proto, fib_index, 1); - - if (is_add) - { - if (bibe) - return VNET_API_ERROR_VALUE_EXIST; - - for (i = 0; i < vec_len (nm->addr_pool); i++) - { - a = nm->addr_pool + i; - if (out_addr->as_u32 != a->addr.as_u32) - continue; - switch (p) - { -#define _(N, j, n, s) \ - case SNAT_PROTOCOL_##N: \ - if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \ - out_port)) \ - return VNET_API_ERROR_INVALID_VALUE; \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \ - out_port, 1); \ - if (out_port > 1024) \ - a->busy_##n##_ports++; \ - break; - foreach_snat_protocol -#undef _ - default: - memset (&addr, 0, sizeof (addr)); - addr.ip4.as_u32 = out_addr->as_u32; - if (nat64_db_bib_entry_find - (&nm->db, &addr, 0, proto, fib_index, 0)) - return VNET_API_ERROR_INVALID_VALUE; - } - break; - } - bibe = - nat64_db_bib_entry_create (&nm->db, in_addr, out_addr, - clib_host_to_net_u16 (in_port), - clib_host_to_net_u16 (out_port), fib_index, - proto, 1); - if (!bibe) - return VNET_API_ERROR_UNSPECIFIED; - } - else - { - if (!bibe) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - nat64_free_out_addr_and_port (out_addr, out_port, p); - nat64_db_bib_entry_free (&nm->db, bibe); - } - - return 0; -} - -int -nat64_set_udp_timeout (u32 timeout) -{ - nat64_main_t *nm = &nat64_main; - - if (timeout == 0) - nm->udp_timeout = SNAT_UDP_TIMEOUT; - else if (timeout < SNAT_UDP_TIMEOUT_MIN) - return VNET_API_ERROR_INVALID_VALUE; - else - nm->udp_timeout = timeout; - - return 0; -} - -u32 -nat64_get_udp_timeout (void) -{ - nat64_main_t *nm = &nat64_main; - - return nm->udp_timeout; -} - -int -nat64_set_icmp_timeout (u32 timeout) -{ - nat64_main_t *nm = &nat64_main; - - if (timeout == 0) - nm->icmp_timeout = SNAT_ICMP_TIMEOUT; - else - nm->icmp_timeout = timeout; - - return 0; -} - -u32 -nat64_get_icmp_timeout (void) -{ - nat64_main_t *nm = &nat64_main; - - return nm->icmp_timeout; -} - -int -nat64_set_tcp_timeouts (u32 trans, u32 est, u32 incoming_syn) -{ - nat64_main_t *nm = &nat64_main; - - if (trans == 0) - nm->tcp_trans_timeout = SNAT_TCP_TRANSITORY_TIMEOUT; - else - nm->tcp_trans_timeout = trans; - - if (est == 0) - nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; - else - nm->tcp_est_timeout = est; - - if (incoming_syn == 0) - nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN; - else - nm->tcp_incoming_syn_timeout = incoming_syn; - - return 0; -} - -u32 -nat64_get_tcp_trans_timeout (void) -{ - nat64_main_t *nm = &nat64_main; - - return nm->tcp_trans_timeout; -} - -u32 -nat64_get_tcp_est_timeout (void) -{ - nat64_main_t *nm = &nat64_main; - - return nm->tcp_est_timeout; -} - -u32 -nat64_get_tcp_incoming_syn_timeout (void) -{ - nat64_main_t *nm = &nat64_main; - - return nm->tcp_incoming_syn_timeout; -} - -void -nat64_session_reset_timeout (nat64_db_st_entry_t * ste, vlib_main_t * vm) -{ - nat64_main_t *nm = &nat64_main; - u32 now = (u32) vlib_time_now (vm); - - switch (ip_proto_to_snat_proto (ste->proto)) - { - case SNAT_PROTOCOL_ICMP: - ste->expire = now + nm->icmp_timeout; - return; - case SNAT_PROTOCOL_TCP: - { - switch (ste->tcp_state) - { - case NAT64_TCP_STATE_V4_INIT: - case NAT64_TCP_STATE_V6_INIT: - case NAT64_TCP_STATE_V4_FIN_RCV: - case NAT64_TCP_STATE_V6_FIN_RCV: - case NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV: - case NAT64_TCP_STATE_TRANS: - ste->expire = now + nm->tcp_trans_timeout; - return; - case NAT64_TCP_STATE_ESTABLISHED: - ste->expire = now + nm->tcp_est_timeout; - return; - default: - return; - } - } - case SNAT_PROTOCOL_UDP: - ste->expire = now + nm->udp_timeout; - return; - default: - ste->expire = now + nm->udp_timeout; - return; - } -} - -void -nat64_tcp_session_set_state (nat64_db_st_entry_t * ste, tcp_header_t * tcp, - u8 is_ip6) -{ - switch (ste->tcp_state) - { - case NAT64_TCP_STATE_CLOSED: - { - if (tcp->flags & TCP_FLAG_SYN) - { - if (is_ip6) - ste->tcp_state = NAT64_TCP_STATE_V6_INIT; - else - ste->tcp_state = NAT64_TCP_STATE_V4_INIT; - } - return; - } - case NAT64_TCP_STATE_V4_INIT: - { - if (is_ip6 && (tcp->flags & TCP_FLAG_SYN)) - ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED; - return; - } - case NAT64_TCP_STATE_V6_INIT: - { - if (!is_ip6 && (tcp->flags & TCP_FLAG_SYN)) - ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED; - return; - } - case NAT64_TCP_STATE_ESTABLISHED: - { - if (tcp->flags & TCP_FLAG_FIN) - { - if (is_ip6) - ste->tcp_state = NAT64_TCP_STATE_V6_FIN_RCV; - else - ste->tcp_state = NAT64_TCP_STATE_V4_FIN_RCV; - } - else if (tcp->flags & TCP_FLAG_RST) - { - ste->tcp_state = NAT64_TCP_STATE_TRANS; - } - return; - } - case NAT64_TCP_STATE_V4_FIN_RCV: - { - if (is_ip6 && (tcp->flags & TCP_FLAG_FIN)) - ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV; - return; - } - case NAT64_TCP_STATE_V6_FIN_RCV: - { - if (!is_ip6 && (tcp->flags & TCP_FLAG_FIN)) - ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV; - return; - } - case NAT64_TCP_STATE_TRANS: - { - if (!(tcp->flags & TCP_FLAG_RST)) - ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED; - return; - } - default: - return; - } -} - -int -nat64_add_del_prefix (ip6_address_t * prefix, u8 plen, u32 vrf_id, u8 is_add) -{ - nat64_main_t *nm = &nat64_main; - nat64_prefix_t *p = 0; - int i; - - /* Verify prefix length */ - if (plen != 32 && plen != 40 && plen != 48 && plen != 56 && plen != 64 - && plen != 96) - return VNET_API_ERROR_INVALID_VALUE; - - /* Check if tenant already have prefix */ - for (i = 0; i < vec_len (nm->pref64); i++) - { - if (nm->pref64[i].vrf_id == vrf_id) - { - p = nm->pref64 + i; - break; - } - } - - if (is_add) - { - if (!p) - { - vec_add2 (nm->pref64, p, 1); - p->fib_index = - fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id); - p->vrf_id = vrf_id; - } - - p->prefix.as_u64[0] = prefix->as_u64[0]; - p->prefix.as_u64[1] = prefix->as_u64[1]; - p->plen = plen; - } - else - { - if (!p) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - vec_del1 (nm->pref64, i); - } - - return 0; -} - -void -nat64_prefix_walk (nat64_prefix_walk_fn_t fn, void *ctx) -{ - nat64_main_t *nm = &nat64_main; - nat64_prefix_t *p = 0; - - /* *INDENT-OFF* */ - vec_foreach (p, nm->pref64) - { - if (fn (p, ctx)) - break; - }; - /* *INDENT-ON* */ -} - -void -nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index) -{ - nat64_main_t *nm = &nat64_main; - nat64_prefix_t *p, *gp = 0, *prefix = 0; - - /* *INDENT-OFF* */ - vec_foreach (p, nm->pref64) - { - if (p->fib_index == fib_index) - { - prefix = p; - break; - } - - if (p->fib_index == 0) - gp = p; - }; - /* *INDENT-ON* */ - - if (!prefix) - prefix = gp; - - if (prefix) - { - memset (ip6, 0, 16); - memcpy (ip6, &p->prefix, p->plen); - switch (p->plen) - { - case 32: - ip6->as_u32[1] = ip4->as_u32; - break; - case 40: - ip6->as_u8[5] = ip4->as_u8[0]; - ip6->as_u8[6] = ip4->as_u8[1]; - ip6->as_u8[7] = ip4->as_u8[2]; - ip6->as_u8[9] = ip4->as_u8[3]; - break; - case 48: - ip6->as_u8[6] = ip4->as_u8[0]; - ip6->as_u8[7] = ip4->as_u8[1]; - ip6->as_u8[9] = ip4->as_u8[2]; - ip6->as_u8[10] = ip4->as_u8[3]; - break; - case 56: - ip6->as_u8[7] = ip4->as_u8[0]; - ip6->as_u8[9] = ip4->as_u8[1]; - ip6->as_u8[10] = ip4->as_u8[2]; - ip6->as_u8[11] = ip4->as_u8[3]; - break; - case 64: - ip6->as_u8[9] = ip4->as_u8[0]; - ip6->as_u8[10] = ip4->as_u8[1]; - ip6->as_u8[11] = ip4->as_u8[2]; - ip6->as_u8[12] = ip4->as_u8[3]; - break; - case 96: - ip6->as_u32[3] = ip4->as_u32; - break; - default: - clib_warning ("invalid prefix length"); - break; - } - } - else - { - memcpy (ip6, well_known_prefix, 16); - ip6->as_u32[3] = ip4->as_u32; - } -} - -void -nat64_extract_ip4 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index) -{ - nat64_main_t *nm = &nat64_main; - nat64_prefix_t *p, *gp = 0; - u8 plen = 0; - - /* *INDENT-OFF* */ - vec_foreach (p, nm->pref64) - { - if (p->fib_index == fib_index) - { - plen = p->plen; - break; - } - - if (p->vrf_id == 0) - gp = p; - }; - /* *INDENT-ON* */ - - if (!plen) - { - if (gp) - plen = gp->plen; - else - plen = 96; - } - - switch (plen) - { - case 32: - ip4->as_u32 = ip6->as_u32[1]; - break; - case 40: - ip4->as_u8[0] = ip6->as_u8[5]; - ip4->as_u8[1] = ip6->as_u8[6]; - ip4->as_u8[2] = ip6->as_u8[7]; - ip4->as_u8[3] = ip6->as_u8[9]; - break; - case 48: - ip4->as_u8[0] = ip6->as_u8[6]; - ip4->as_u8[1] = ip6->as_u8[7]; - ip4->as_u8[2] = ip6->as_u8[9]; - ip4->as_u8[3] = ip6->as_u8[10]; - break; - case 56: - ip4->as_u8[0] = ip6->as_u8[7]; - ip4->as_u8[1] = ip6->as_u8[9]; - ip4->as_u8[2] = ip6->as_u8[10]; - ip4->as_u8[3] = ip6->as_u8[11]; - break; - case 64: - ip4->as_u8[0] = ip6->as_u8[9]; - ip4->as_u8[1] = ip6->as_u8[10]; - ip4->as_u8[2] = ip6->as_u8[11]; - ip4->as_u8[3] = ip6->as_u8[12]; - break; - case 96: - ip4->as_u32 = ip6->as_u32[3]; - break; - default: - clib_warning ("invalid prefix length"); - break; - } -} - -/** - * @brief The 'nat64-expire-walk' process's main loop. - * - * Check expire time for NAT64 sessions. - */ -static uword -nat64_expire_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, - vlib_frame_t * f) -{ - nat64_main_t *nm = &nat64_main; - - while (!nm->is_disabled) - { - vlib_process_wait_for_event_or_clock (vm, 10.0); - vlib_process_get_events (vm, NULL); - u32 now = (u32) vlib_time_now (vm); - - nad64_db_st_free_expired (&nm->db, now); - } - - return 0; -} - -static vlib_node_registration_t nat64_expire_walk_node; - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (nat64_expire_walk_node, static) = { - .function = nat64_expire_walk_fn, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "nat64-expire-walk", -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/nat64.h b/src/plugins/snat/nat64.h deleted file mode 100644 index 771b9075405..00000000000 --- a/src/plugins/snat/nat64.h +++ /dev/null @@ -1,322 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief NAT64 global declarations - */ -#ifndef __included_nat64_h__ -#define __included_nat64_h__ - -#include <snat/snat.h> -#include <snat/nat64_db.h> - -#define foreach_nat64_tcp_ses_state \ - _(0, CLOSED, "closed") \ - _(1, V4_INIT, "v4-init") \ - _(2, V6_INIT, "v6-init") \ - _(3, ESTABLISHED, "established") \ - _(4, V4_FIN_RCV, "v4-fin-rcv") \ - _(5, V6_FIN_RCV, "v6-fin-rcv") \ - _(6, V6_FIN_V4_FIN_RCV, "v6-fin-v4-fin-rcv") \ - _(7, TRANS, "trans") - -typedef enum -{ -#define _(v, N, s) NAT64_TCP_STATE_##N = v, - foreach_nat64_tcp_ses_state -#undef _ -} nat64_tcp_ses_state_t; - -typedef struct -{ - ip6_address_t prefix; - u8 plen; - u32 vrf_id; - u32 fib_index; -} nat64_prefix_t; - -typedef struct -{ - /** Interface pool */ - snat_interface_t *interfaces; - - /** Address pool vector */ - snat_address_t *addr_pool; - - /** Pref64 vector */ - nat64_prefix_t *pref64; - - /** BIB and session DB */ - nat64_db_t db; - - /* values of various timeouts */ - u32 udp_timeout; - u32 icmp_timeout; - u32 tcp_trans_timeout; - u32 tcp_est_timeout; - u32 tcp_incoming_syn_timeout; - - u8 is_disabled; - - snat_main_t *sm; -} nat64_main_t; - -extern nat64_main_t nat64_main; -extern vlib_node_registration_t nat64_in2out_node; -extern vlib_node_registration_t nat64_out2in_node; - -/** - * @brief Add/delete address to NAT64 pool. - * - * @param addr IPv4 address. - * @param vrf_id VRF id of tenant, ~0 means independent of VRF. - * @param is_add 1 if add, 0 if delete. - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add); - -/** - * @brief Call back function when walking addresses in NAT64 pool, non-zero - * return value stop walk. - */ -typedef int (*nat64_pool_addr_walk_fn_t) (snat_address_t * addr, void *ctx); - -/** - * @brief Walk NAT64 pool. - * - * @param fn The function to invoke on each entry visited. - * @param ctx A context passed in the visit function. - */ -void nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx); - -/** - * @brief Enable/disable NAT64 feature on the interface. - * - * @param sw_if_index Index of the interface. - * @param is_inside 1 if inside, 0 if outside. - * @param is_add 1 if add, 0 if delete. - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add); - -/** - * @brief Call back function when walking interfaces with NAT64 feature, - * non-zero return value stop walk. - */ -typedef int (*nat64_interface_walk_fn_t) (snat_interface_t * i, void *ctx); - -/** - * @brief Walk NAT64 interfaces. - * - * @param fn The function to invoke on each entry visited. - * @param ctx A context passed in the visit function. - */ -void nat64_interfaces_walk (nat64_interface_walk_fn_t fn, void *ctx); - -/** - * @brief Initialize NAT64. - * - * @param vm vlib main. - * - * @return error code. - */ -clib_error_t *nat64_init (vlib_main_t * vm); - -/** - * @brief Add/delete static NAT64 BIB entry. - * - * @param in_addr Inside IPv6 address. - * @param out_addr Outside IPv4 address. - * @param in_port Inside port number. - * @param out_port Outside port number. - * @param proto L4 protocol. - * @param vrf_id VRF id of tenant. - * @param is_add 1 if add, 0 if delete. - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_add_del_static_bib_entry (ip6_address_t * in_addr, - ip4_address_t * out_addr, u16 in_port, - u16 out_port, u8 proto, u32 vrf_id, - u8 is_add); - -/** - * @brief Alloce IPv4 address and port pair from NAT64 pool. - * - * @param fib_index FIB index of tenant. - * @param proto L4 protocol. - * @param addr Allocated IPv4 address. - * @param port Allocated port number. - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_alloc_out_addr_and_port (u32 fib_index, snat_protocol_t proto, - ip4_address_t * addr, u16 * port); - -/** - * @brief Free IPv4 address and port pair from NAT64 pool. - * - * @param addr IPv4 address to free. - * @param port Port number to free. - * @param proto L4 protocol. - * - * @returns 0 on success, non-zero value otherwise. - */ -void nat64_free_out_addr_and_port (ip4_address_t * addr, u16 port, - snat_protocol_t proto); - -/** - * @brief Set UDP session timeout. - * - * @param timeout Timeout value in seconds (if 0 reset to default value 300sec). - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_set_udp_timeout (u32 timeout); - -/** - * @brief Get UDP session timeout. - * - * @returns UDP session timeout in seconds. - */ -u32 nat64_get_udp_timeout (void); - -/** - * @brief Set ICMP session timeout. - * - * @param timeout Timeout value in seconds (if 0 reset to default value 60sec). - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_set_icmp_timeout (u32 timeout); - -/** - * @brief Get ICMP session timeout. - * - * @returns ICMP session timeout in seconds. - */ -u32 nat64_get_icmp_timeout (void); - -/** - * @brief Set TCP session timeouts. - * - * @param trans Transitory timeout in seconds (if 0 reset to default value 240sec). - * @param est Established timeout in seconds (if 0 reset to default value 7440sec). - * @param incoming_syn Incoming SYN timeout in seconds (if 0 reset to default value 6sec). - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_set_tcp_timeouts (u32 trans, u32 est, u32 incoming_syn); - -/** - * @brief Get TCP transitory timeout. - * - * @returns TCP transitory timeout in seconds. - */ -u32 nat64_get_tcp_trans_timeout (void); - -/** - * @brief Get TCP established timeout. - * - * @returns TCP established timeout in seconds. - */ -u32 nat64_get_tcp_est_timeout (void); - -/** - * @brief Get TCP incoming SYN timeout. - * - * @returns TCP incoming SYN timeout in seconds. - */ -u32 nat64_get_tcp_incoming_syn_timeout (void); - -/** - * @brief Reset NAT64 session timeout. - * - * @param ste Session table entry. - * @param vm VLIB main. - **/ -void nat64_session_reset_timeout (nat64_db_st_entry_t * ste, - vlib_main_t * vm); - -/** - * @brief Set NAT64 TCP session state. - * - * @param ste Session table entry. - * @param tcp TCP header. - * @param is_ip6 1 if IPv6 packet, 0 if IPv4. - */ -void nat64_tcp_session_set_state (nat64_db_st_entry_t * ste, - tcp_header_t * tcp, u8 is_ip6); - -/** - * @brief Add/delete NAT64 prefix. - * - * @param prefix NAT64 prefix. - * @param plen Prefix length. - * @param vrf_id VRF id of tenant. - * @param is_add 1 if add, 0 if delete. - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_add_del_prefix (ip6_address_t * prefix, u8 plen, u32 vrf_id, - u8 is_add); - -/** - * @brief Call back function when walking addresses in NAT64 prefixes, non-zero - * return value stop walk. - */ -typedef int (*nat64_prefix_walk_fn_t) (nat64_prefix_t * pref64, void *ctx); - -/** - * @brief Walk NAT64 prefixes. - * - * @param fn The function to invoke on each entry visited. - * @param ctx A context passed in the visit function. - */ -void nat64_prefix_walk (nat64_prefix_walk_fn_t fn, void *ctx); - -/** - * Compose IPv4-embedded IPv6 addresses. - * @param ip6 IPv4-embedded IPv6 addresses. - * @param ip4 IPv4 address. - * @param fib_index Tenant FIB index. - */ -void nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, - u32 fib_index); - -/** - * Extract IPv4 address from the IPv4-embedded IPv6 addresses. - * - * @param ip6 IPv4-embedded IPv6 addresses. - * @param ip4 IPv4 address. - * @param fib_index Tenant FIB index. - */ -void nat64_extract_ip4 (ip6_address_t * ip6, ip4_address_t * ip4, - u32 fib_index); - -#define u8_ptr_add(ptr, index) (((u8 *)ptr) + index) -#define u16_net_add(u, val) clib_host_to_net_u16(clib_net_to_host_u16(u) + (val)) - -#endif /* __included_nat64_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/nat64_cli.c b/src/plugins/snat/nat64_cli.c deleted file mode 100644 index ca60b12c189..00000000000 --- a/src/plugins/snat/nat64_cli.c +++ /dev/null @@ -1,983 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief NAT64 CLI - */ - -#include <snat/nat64.h> -#include <snat/snat.h> -#include <vnet/fib/fib_table.h> - -static clib_error_t * -nat64_add_del_pool_addr_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t start_addr, end_addr, this_addr; - u32 start_host_order, end_host_order; - int i, count, rv; - u32 vrf_id = ~0; - u8 is_add = 1; - clib_error_t *error = 0; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - 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, "tenant-vrf %u", &vrf_id)) - ; - 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 - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - start_host_order = clib_host_to_net_u32 (start_addr.as_u32); - end_host_order = clib_host_to_net_u32 (end_addr.as_u32); - - if (end_host_order < start_host_order) - { - error = clib_error_return (0, "end address less than start address"); - goto done; - } - - count = (end_host_order - start_host_order) + 1; - this_addr = start_addr; - - for (i = 0; i < count; i++) - { - rv = nat64_add_del_pool_addr (&this_addr, vrf_id, is_add); - - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = - clib_error_return (0, "NAT64 pool address %U not exist.", - format_ip4_address, &this_addr); - goto done; - case VNET_API_ERROR_VALUE_EXIST: - error = - clib_error_return (0, "NAT64 pool address %U exist.", - format_ip4_address, &this_addr); - goto done; - default: - break; - - } - increment_v4_address (&this_addr); - } - -done: - unformat_free (line_input); - - return error; -} - -static int -nat64_cli_pool_walk (snat_address_t * ap, void *ctx) -{ - vlib_main_t *vm = ctx; - - if (ap->fib_index != ~0) - { - fib_table_t *fib; - fib = fib_table_get (ap->fib_index, FIB_PROTOCOL_IP6); - if (!fib) - return -1; - vlib_cli_output (vm, " %U tenant VRF: %u", format_ip4_address, - &ap->addr, fib->ft_table_id); - } - else - vlib_cli_output (vm, " %U", format_ip4_address, &ap->addr); - - return 0; -} - -static clib_error_t * -nat64_show_pool_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - vlib_cli_output (vm, "NAT64 pool:"); - nat64_pool_addr_walk (nat64_cli_pool_walk, vm); - - return 0; -} - -static clib_error_t * -nat64_interface_feature_command_fn (vlib_main_t * vm, - unformat_input_t * - input, vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - unformat_input_t _line_input, *line_input = &_line_input; - vnet_main_t *vnm = vnet_get_main (); - clib_error_t *error = 0; - u32 sw_if_index; - u32 *inside_sw_if_indices = 0; - u32 *outside_sw_if_indices = 0; - u8 is_add = 1; - int i, rv; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "in %U", unformat_vnet_sw_interface, - vnm, &sw_if_index)) - vec_add1 (inside_sw_if_indices, sw_if_index); - else if (unformat (line_input, "out %U", unformat_vnet_sw_interface, - vnm, &sw_if_index)) - vec_add1 (outside_sw_if_indices, sw_if_index); - else if (unformat (line_input, "del")) - is_add = 0; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (vec_len (inside_sw_if_indices)) - { - for (i = 0; i < vec_len (inside_sw_if_indices); i++) - { - sw_if_index = inside_sw_if_indices[i]; - rv = nat64_add_del_interface (sw_if_index, 1, is_add); - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = - clib_error_return (0, "%U NAT64 feature not enabled.", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); - goto done; - case VNET_API_ERROR_VALUE_EXIST: - error = - clib_error_return (0, "%U NAT64 feature already enabled.", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); - goto done; - case VNET_API_ERROR_INVALID_VALUE: - case VNET_API_ERROR_INVALID_VALUE_2: - error = - clib_error_return (0, - "%U NAT64 feature enable/disable failed.", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); - goto done; - default: - break; - - } - } - } - - if (vec_len (outside_sw_if_indices)) - { - for (i = 0; i < vec_len (outside_sw_if_indices); i++) - { - sw_if_index = outside_sw_if_indices[i]; - rv = nat64_add_del_interface (sw_if_index, 0, is_add); - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = - clib_error_return (0, "%U NAT64 feature not enabled.", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); - goto done; - case VNET_API_ERROR_VALUE_EXIST: - error = - clib_error_return (0, "%U NAT64 feature already enabled.", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); - goto done; - case VNET_API_ERROR_INVALID_VALUE: - case VNET_API_ERROR_INVALID_VALUE_2: - error = - clib_error_return (0, - "%U NAT64 feature enable/disable failed.", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); - goto done; - default: - break; - - } - } - } - -done: - unformat_free (line_input); - vec_free (inside_sw_if_indices); - vec_free (outside_sw_if_indices); - - return error; -} - -static int -nat64_cli_interface_walk (snat_interface_t * i, void *ctx) -{ - vlib_main_t *vm = ctx; - vnet_main_t *vnm = vnet_get_main (); - - vlib_cli_output (vm, " %U %s", format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, i->sw_if_index), - i->is_inside ? "in" : "out"); - return 0; -} - -static clib_error_t * -nat64_show_interfaces_command_fn (vlib_main_t * vm, - unformat_input_t * - input, vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - vlib_cli_output (vm, "NAT64 interfaces:"); - nat64_interfaces_walk (nat64_cli_interface_walk, vm); - - return 0; -} - -static clib_error_t * -nat64_add_del_static_bib_command_fn (vlib_main_t * - vm, - unformat_input_t - * input, vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = 0; - u8 is_add = 1; - ip6_address_t in_addr; - ip4_address_t out_addr; - u16 in_port = 0; - u16 out_port = 0; - u32 vrf_id = 0, protocol; - snat_protocol_t proto = 0; - u8 p = 0; - int rv; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U %u", unformat_ip6_address, - &in_addr, &in_port)) - ; - else if (unformat (line_input, "%U %u", unformat_ip4_address, - &out_addr, &out_port)) - ; - else if (unformat (line_input, "vrf %u", &vrf_id)) - ; - else if (unformat (line_input, "%U", unformat_snat_protocol, &proto)) - ; - else - if (unformat - (line_input, "%U %U %u", unformat_ip6_address, &in_addr, - unformat_ip4_address, &out_addr, &protocol)) - p = (u8) protocol; - else if (unformat (line_input, "del")) - is_add = 0; - else - { - error = clib_error_return (0, "unknown input: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (!p) - { - if (!in_port) - { - error = - clib_error_return (0, "inside port and address must be set"); - goto done; - } - - if (!out_port) - { - error = - clib_error_return (0, "outside port and address must be set"); - goto done; - } - - p = snat_proto_to_ip_proto (proto); - } - - rv = - nat64_add_del_static_bib_entry (&in_addr, &out_addr, in_port, out_port, p, - vrf_id, is_add); - - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = clib_error_return (0, "NAT64 BIB entry not exist."); - goto done; - case VNET_API_ERROR_VALUE_EXIST: - error = clib_error_return (0, "NAT64 BIB entry exist."); - goto done; - case VNET_API_ERROR_UNSPECIFIED: - error = clib_error_return (0, "Crerate NAT64 BIB entry failed."); - goto done; - case VNET_API_ERROR_INVALID_VALUE: - error = - clib_error_return (0, "Outside addres %U and port %u already in use.", - format_ip4_address, &out_addr, out_port); - goto done; - default: - break; - } - -done: - unformat_free (line_input); - - return error; -} - -static int -nat64_cli_bib_walk (nat64_db_bib_entry_t * bibe, void *ctx) -{ - vlib_main_t *vm = ctx; - fib_table_t *fib; - - fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6); - if (!fib) - return -1; - - switch (bibe->proto) - { - case IP_PROTOCOL_ICMP: - case IP_PROTOCOL_TCP: - case IP_PROTOCOL_UDP: - vlib_cli_output (vm, " %U %u %U %u protocol %U vrf %u %s %u sessions", - format_ip6_address, &bibe->in_addr, - clib_net_to_host_u16 (bibe->in_port), - format_ip4_address, &bibe->out_addr, - clib_net_to_host_u16 (bibe->out_port), - format_snat_protocol, - ip_proto_to_snat_proto (bibe->proto), fib->ft_table_id, - bibe->is_static ? "static" : "dynamic", bibe->ses_num); - break; - default: - vlib_cli_output (vm, " %U %U protocol %u vrf %u %s %u sessions", - format_ip6_address, &bibe->in_addr, - format_ip4_address, &bibe->out_addr, - bibe->proto, fib->ft_table_id, - bibe->is_static ? "static" : "dynamic", bibe->ses_num); - } - return 0; -} - -static clib_error_t * -nat64_show_bib_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = 0; - u32 proto = ~0; - u8 p = 255; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - if (unformat (line_input, "%U", unformat_snat_protocol, &proto)) - p = snat_proto_to_ip_proto (proto); - else if (unformat (line_input, "unknown")) - p = 0; - else if (unformat (line_input, "all")) - ; - else - { - error = clib_error_return (0, "unknown input: '%U'", - format_unformat_error, line_input); - goto done; - } - - if (p == 255) - vlib_cli_output (vm, "NAT64 BIB entries:"); - else - vlib_cli_output (vm, "NAT64 %U BIB entries:", format_snat_protocol, - proto); - nat64_db_bib_walk (&nm->db, p, nat64_cli_bib_walk, vm); - -done: - unformat_free (line_input); - - return error; -} - -static clib_error_t * -nat64_set_timeouts_command_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = 0; - u32 timeout, tcp_trans, tcp_est, tcp_incoming_syn; - - tcp_trans = nat64_get_tcp_trans_timeout (); - tcp_est = nat64_get_tcp_est_timeout (); - tcp_incoming_syn = nat64_get_tcp_incoming_syn_timeout (); - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "udp %u", &timeout)) - { - if (nat64_set_udp_timeout (timeout)) - { - error = clib_error_return (0, "Invalid UDP timeout value"); - goto done; - } - } - else if (unformat (line_input, "icmp %u", &timeout)) - { - if (nat64_set_icmp_timeout (timeout)) - { - error = clib_error_return (0, "Invalid ICMP timeout value"); - goto done; - } - } - else if (unformat (line_input, "tcp-trans %u", &tcp_trans)) - { - if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn)) - { - error = - clib_error_return (0, "Invalid TCP transitory tiemout value"); - goto done; - } - } - else if (unformat (line_input, "tcp-est %u", &tcp_est)) - { - if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn)) - { - error = - clib_error_return (0, - "Invalid TCP established tiemout value"); - goto done; - } - } - else - if (unformat (line_input, "tcp-incoming-syn %u", &tcp_incoming_syn)) - { - if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn)) - { - error = - clib_error_return (0, - "Invalid TCP incoming SYN tiemout value"); - goto done; - } - } - else if (unformat (line_input, "reset")) - { - nat64_set_udp_timeout (0); - nat64_set_icmp_timeout (0); - nat64_set_tcp_timeouts (0, 0, 0); - } - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - -done: - unformat_free (line_input); - - return error; -} - -static clib_error_t * -nat64_show_timeouts_command_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - vlib_cli_output (vm, "NAT64 session timeouts:"); - vlib_cli_output (vm, " UDP %usec", nat64_get_udp_timeout ()); - vlib_cli_output (vm, " ICMP %usec", nat64_get_icmp_timeout ()); - vlib_cli_output (vm, " TCP transitory %usec", - nat64_get_tcp_trans_timeout ()); - vlib_cli_output (vm, " TCP established %usec", - nat64_get_tcp_est_timeout ()); - vlib_cli_output (vm, " TCP incoming SYN %usec", - nat64_get_tcp_incoming_syn_timeout ()); - - return 0; -} - -static int -nat64_cli_st_walk (nat64_db_st_entry_t * ste, void *ctx) -{ - vlib_main_t *vm = ctx; - nat64_main_t *nm = &nat64_main; - nat64_db_bib_entry_t *bibe; - fib_table_t *fib; - - bibe = nat64_db_bib_entry_by_index (&nm->db, ste->proto, ste->bibe_index); - if (!bibe) - return -1; - - fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6); - if (!fib) - return -1; - - u32 vrf_id = fib->ft_table_id; - - if (ste->proto == IP_PROTOCOL_ICMP) - vlib_cli_output (vm, " %U %U %u %U %U %u protocol %U vrf %u", - format_ip6_address, &bibe->in_addr, - format_ip6_address, &ste->in_r_addr, - clib_net_to_host_u16 (bibe->in_port), - format_ip4_address, &bibe->out_addr, - format_ip4_address, &ste->out_r_addr, - clib_net_to_host_u16 (bibe->out_port), - format_snat_protocol, - ip_proto_to_snat_proto (bibe->proto), vrf_id); - else if (ste->proto == IP_PROTOCOL_TCP || ste->proto == IP_PROTOCOL_UDP) - vlib_cli_output (vm, " %U %u %U %u %U %u %U %u protcol %U vrf %u", - format_ip6_address, &bibe->in_addr, - clib_net_to_host_u16 (bibe->in_port), - format_ip6_address, &ste->in_r_addr, - clib_net_to_host_u16 (ste->r_port), - format_ip4_address, &bibe->out_addr, - clib_net_to_host_u16 (bibe->out_port), - format_ip4_address, &ste->out_r_addr, - clib_net_to_host_u16 (ste->r_port), - format_snat_protocol, - ip_proto_to_snat_proto (bibe->proto), vrf_id); - else - vlib_cli_output (vm, " %U %U %U %U protocol %u vrf %u", - format_ip6_address, &bibe->in_addr, - format_ip6_address, &ste->in_r_addr, - format_ip4_address, &bibe->out_addr, - format_ip4_address, &ste->out_r_addr, - bibe->proto, vrf_id); - - return 0; -} - -static clib_error_t * -nat64_show_st_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = 0; - u32 proto = ~0; - u8 p = 255; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - if (unformat (line_input, "%U", unformat_snat_protocol, &proto)) - p = snat_proto_to_ip_proto (proto); - else if (unformat (line_input, "unknown")) - p = 0; - else if (unformat (line_input, "all")) - ; - else - { - error = clib_error_return (0, "unknown input: '%U'", - format_unformat_error, line_input); - goto done; - } - - if (p == 255) - vlib_cli_output (vm, "NAT64 sessions:"); - else - vlib_cli_output (vm, "NAT64 %U sessions:", format_snat_protocol, proto); - nat64_db_st_walk (&nm->db, p, nat64_cli_st_walk, vm); - -done: - unformat_free (line_input); - - return error; -} - -static clib_error_t * -nat64_add_del_prefix_command_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - clib_error_t *error = 0; - unformat_input_t _line_input, *line_input = &_line_input; - u8 is_add = 1; - u32 vrf_id = 0; - ip6_address_t prefix; - u32 plen = 0; - int rv; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U/%u", unformat_ip6_address, &prefix, &plen)) - ; - else if (unformat (line_input, "tenant-vrf %u", &vrf_id)) - ; - else if (unformat (line_input, "del")) - is_add = 0; - else - { - error = clib_error_return (0, "unknown input: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (!plen) - { - error = clib_error_return (0, "NAT64 prefix must be set."); - goto done; - } - - rv = nat64_add_del_prefix (&prefix, (u8) plen, vrf_id, is_add); - - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = clib_error_return (0, "NAT64 prefix not exist."); - goto done; - case VNET_API_ERROR_INVALID_VALUE: - error = clib_error_return (0, "Invalid prefix length."); - goto done; - default: - break; - } - -done: - unformat_free (line_input); - - return error; -} - -static int -nat64_cli_prefix_walk (nat64_prefix_t * p, void *ctx) -{ - vlib_main_t *vm = ctx; - - vlib_cli_output (vm, " %U/%u tenant-vrf %u", - format_ip6_address, &p->prefix, p->plen, p->vrf_id); - - return 0; -} - -static clib_error_t * -nat64_show_prefix_command_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return clib_error_return (0, - "NAT64 disabled, multi thread not supported"); - - vlib_cli_output (vm, "NAT64 prefix:"); - nat64_prefix_walk (nat64_cli_prefix_walk, vm); - - return 0; -} - -/* *INDENT-OFF* */ - -/*? - * @cliexpar - * @cliexstart{nat64 add pool address} - * Add/delete NAT64 pool address. - * To add single NAT64 pool address use: - * vpp# nat64 add pool address 10.1.1.10 - * To add NAT64 pool address range use: - * vpp# nat64 add pool address 10.1.1.2 - 10.1.1.5 - * To add NAT64 pool address for specific tenant use: - * vpp# nat64 add pool address 10.1.1.100 tenant-vrf 100 - * @cliexend -?*/ -VLIB_CLI_COMMAND (nat64_add_pool_address_command, static) = { - .path = "nat64 add pool address", - .short_help = "nat64 add pool address <ip4-range-start> [- <ip4-range-end>] " - "[tenant-vrf <vrf-id>] [del]", - .function = nat64_add_del_pool_addr_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show nat64 pool} - * Show NAT64 pool. - * vpp# show nat64 pool - * NAT64 pool: - * 10.1.1.3 tenant VRF: 0 - * 10.1.1.10 tenant VRF: 10 - * @cliexend -?*/ -VLIB_CLI_COMMAND (show_nat64_pool_command, static) = { - .path = "show nat64 pool", - .short_help = "show nat64 pool", - .function = nat64_show_pool_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{set interface nat64} - * Enable/disable NAT64 feature on the interface. - * To enable NAT64 feature with local (IPv6) network interface - * GigabitEthernet0/8/0 and external (IPv4) network interface - * GigabitEthernet0/a/0 use: - * vpp# set interface nat64 in GigabitEthernet0/8/0 out GigabitEthernet0/a/0 - * @cliexend -?*/ -VLIB_CLI_COMMAND (set_interface_nat64_command, static) = { - .path = "set interface nat64", - .short_help = "set interface nat64 in|out <intfc> [del]", - .function = nat64_interface_feature_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show nat64 interfaces} - * Show interfaces with NAT64 feature. - * To show interfaces with NAT64 feature use: - * vpp# show nat64 interfaces - * NAT64 interfaces: - * GigabitEthernet0/8/0 in - * GigabitEthernet0/a/0 out - * @cliexend -?*/ -VLIB_CLI_COMMAND (show_nat64_interfaces_command, static) = { - .path = "show nat64 interfaces", - .short_help = "show nat64 interfaces", - .function = nat64_show_interfaces_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{nat64 add static bib} - * Add/delete NAT64 static BIB entry. - * To create NAT64 satatic BIB entry use: - * vpp# nat64 add static bib 2001:db8:c000:221:: 1234 10.1.1.3 5678 tcp - * vpp# nat64 add static bib 2001:db8:c000:221:: 1234 10.1.1.3 5678 udp vrf 10 - * @cliexend -?*/ -VLIB_CLI_COMMAND (nat64_add_del_static_bib_command, static) = { - .path = "nat64 add static bib", - .short_help = "nat64 add static bib <ip6-addr> <port> <ip4-addr> <port> " - "tcp|udp|icmp [vfr <table-id>] [del]", - .function = nat64_add_del_static_bib_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show nat64 bib} - * Show NAT64 BIB entries. - * To show NAT64 TCP BIB entries use: - * vpp# show nat64 bib tcp - * NAT64 tcp BIB: - * fd01:1::2 6303 10.0.0.3 62303 tcp vrf 0 dynamic 1 sessions - * 2001:db8:c000:221:: 1234 10.1.1.3 5678 tcp vrf 0 static 2 sessions - * To show NAT64 UDP BIB entries use: - * vpp# show nat64 bib udp - * NAT64 udp BIB: - * fd01:1::2 6304 10.0.0.3 10546 udp vrf 0 dynamic 10 sessions - * 2001:db8:c000:221:: 1234 10.1.1.3 5678 udp vrf 10 static 0 sessions - * To show NAT64 ICMP BIB entries use: - * vpp# show nat64 bib icmp - * NAT64 icmp BIB: - * fd01:1::2 6305 10.0.0.3 63209 icmp vrf 10 dynamic 1 sessions - * @cliexend -?*/ -VLIB_CLI_COMMAND (show_nat64_bib_command, static) = { - .path = "show nat64 bib", - .short_help = "show nat64 bib all|tcp|udp|icmp|unknown", - .function = nat64_show_bib_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{set nat64 timeouts} - * Set NAT64 session timeouts (in seconds). - * To set NAT64 session timeoutes use use: - * vpp# set nat64 timeouts udp 200 icmp 30 tcp-trans 250 tcp-est 7450 - * To reset NAT64 session timeoutes to default values use: - * vpp# set nat64 timeouts reset - * @cliexend -?*/ -VLIB_CLI_COMMAND (set_nat64_timeouts_command, static) = { - .path = "set nat64 timeouts", - .short_help = "set nat64 timeouts udp <sec> icmp <sec> tcp-trans <sec> " - "tcp-est <sec> tcp-incoming-syn <sec> | reset", - .function = nat64_set_timeouts_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show nat64 tiemouts} - * Show NAT64 session timeouts: - * vpp# show nat64 tiemouts - * NAT64 session timeouts: - * UDP 300sec - * ICMP 60sec - * TCP transitory 240sec - * TCP established 7440sec - * TCP incoming SYN 6sec - * @cliexend -?*/ -VLIB_CLI_COMMAND (show_nat64_timeouts_command, static) = { - .path = "show nat64 tiemouts", - .short_help = "show nat64 tiemouts", - .function = nat64_show_timeouts_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show nat64 session table} - * Show NAT64 session table. - * To show NAT64 TCP session table use: - * vpp# show nat64 session table tcp - * NAT64 tcp session table: - * fd01:1::2 6303 64:ff9b::ac10:202 20 10.0.0.3 62303 172.16.2.2 20 tcp vrf 0 - * fd01:3::2 6303 64:ff9b::ac10:202 20 10.0.10.3 21300 172.16.2.2 20 tcp vrf 10 - * To show NAT64 UDP session table use: - * #vpp show nat64 session table udp - * NAT64 udp session table: - * fd01:1::2 6304 64:ff9b::ac10:202 20 10.0.0.3 10546 172.16.2.2 20 udp vrf 0 - * fd01:3::2 6304 64:ff9b::ac10:202 20 10.0.10.3 58627 172.16.2.2 20 udp vrf 10 - * fd01:1::2 1235 64:ff9b::a00:3 4023 10.0.0.3 24488 10.0.0.3 4023 udp vrf 0 - * fd01:1::3 23 64:ff9b::a00:3 24488 10.0.0.3 4023 10.0.0.3 24488 udp vrf 0 - * To show NAT64 ICMP session table use: - * #vpp show nat64 session table icmp - * NAT64 icmp session table: - * fd01:1::2 64:ff9b::ac10:202 6305 10.0.0.3 172.16.2.2 63209 icmp vrf 0 - * @cliexend -?*/ -VLIB_CLI_COMMAND (show_nat64_st_command, static) = { - .path = "show nat64 session table", - .short_help = "show nat64 session table all|tcp|udp|icmp|unknown", - .function = nat64_show_st_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{nat64 add prefix} - * Set NAT64 prefix for generating IPv6 representations of IPv4 addresses. - * To set NAT64 global prefix use: - * vpp# nat64 add prefix 2001:db8::/32 - * To set NAT64 prefix for specific tenant use: - * vpp# nat64 add prefix 2001:db8:122:300::/56 tenant-vrf 10 - * @cliexend -?*/ -VLIB_CLI_COMMAND (nat64_add_del_prefix_command, static) = { - .path = "nat64 add prefix", - .short_help = "nat64 add prefix <ip6-prefix>/<plen> [tenant-vrf <vrf-id>] " - "[del]", - .function = nat64_add_del_prefix_command_fn, -}; - -/*? - * @cliexpar - * @cliexstart{show nat64 prefix} - * Show NAT64 prefix. - * To show NAT64 prefix use: - * vpp# show nat64 prefix - * NAT64 prefix: - * 2001:db8::/32 tenant-vrf 0 - * 2001:db8:122:300::/56 tenant-vrf 10 - * @cliexend -?*/ -VLIB_CLI_COMMAND (show_nat64_prefix_command, static) = { - .path = "show nat64 prefix", - .short_help = "show nat64 prefix", - .function = nat64_show_prefix_command_fn, -}; - -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/nat64_db.c b/src/plugins/snat/nat64_db.c deleted file mode 100644 index 9584827e4da..00000000000 --- a/src/plugins/snat/nat64_db.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief NAT64 DB - */ -#include <snat/nat64_db.h> - -int -nat64_db_init (nat64_db_t * db) -{ - u32 bib_buckets = 1024; - u32 bib_memory_size = 128 << 20; - u32 st_buckets = 2048; - u32 st_memory_size = 256 << 20; - - clib_bihash_init_24_8 (&db->bib.in2out, "bib-in2out", bib_buckets, - bib_memory_size); - - clib_bihash_init_24_8 (&db->bib.out2in, "bib-out2in", bib_buckets, - bib_memory_size); - - clib_bihash_init_48_8 (&db->st.in2out, "st-in2out", st_buckets, - st_memory_size); - - clib_bihash_init_48_8 (&db->st.out2in, "st-out2in", st_buckets, - st_memory_size); - - return 0; -} - -nat64_db_bib_entry_t * -nat64_db_bib_entry_create (nat64_db_t * db, ip6_address_t * in_addr, - ip4_address_t * out_addr, u16 in_port, - u16 out_port, u32 fib_index, u8 proto, - u8 is_static) -{ - nat64_db_bib_entry_t *bibe; - nat64_db_bib_entry_key_t bibe_key; - clib_bihash_kv_24_8_t kv; - - /* create pool entry */ - switch (ip_proto_to_snat_proto (proto)) - { -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - pool_get (db->bib._##n##_bib, bibe); \ - kv.value = bibe - db->bib._##n##_bib; \ - break; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - default: - pool_get (db->bib._unk_proto_bib, bibe); - kv.value = bibe - db->bib._unk_proto_bib; - break; - } - memset (bibe, 0, sizeof (*bibe)); - bibe->in_addr.as_u64[0] = in_addr->as_u64[0]; - bibe->in_addr.as_u64[1] = in_addr->as_u64[1]; - bibe->in_port = in_port; - bibe->out_addr.as_u32 = out_addr->as_u32; - bibe->out_port = out_port; - bibe->fib_index = fib_index; - bibe->proto = proto; - bibe->is_static = is_static; - - /* create hash lookup */ - bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0]; - bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1]; - bibe_key.fib_index = bibe->fib_index; - bibe_key.port = bibe->in_port; - bibe_key.proto = bibe->proto; - bibe_key.rsvd = 0; - kv.key[0] = bibe_key.as_u64[0]; - kv.key[1] = bibe_key.as_u64[1]; - kv.key[2] = bibe_key.as_u64[2]; - clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 1); - - memset (&bibe_key.addr, 0, sizeof (bibe_key.addr)); - bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32; - bibe_key.fib_index = 0; - bibe_key.port = bibe->out_port; - kv.key[0] = bibe_key.as_u64[0]; - kv.key[1] = bibe_key.as_u64[1]; - kv.key[2] = bibe_key.as_u64[2]; - clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 1); - - return bibe; -} - -void -nat64_db_bib_entry_free (nat64_db_t * db, nat64_db_bib_entry_t * bibe) -{ - nat64_db_bib_entry_key_t bibe_key; - clib_bihash_kv_24_8_t kv; - nat64_db_bib_entry_t *bib; - u32 *ste_to_be_free = 0, *ste_index, bibe_index; - nat64_db_st_entry_t *st, *ste; - - switch (ip_proto_to_snat_proto (bibe->proto)) - { -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - bib = db->bib._##n##_bib; \ - st = db->st._##n##_st; \ - break; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - default: - bib = db->bib._unk_proto_bib; - st = db->st._unk_proto_st; - break; - } - - bibe_index = bibe - bib; - - /* delete ST entries for static BIB entry */ - if (bibe->is_static) - { - pool_foreach (ste, st, ( - { - if (ste->bibe_index == bibe_index) - vec_add1 (ste_to_be_free, ste - st);} - )); - vec_foreach (ste_index, ste_to_be_free) - nat64_db_st_entry_free (db, pool_elt_at_index (st, ste_index[0])); - vec_free (ste_to_be_free); - } - - /* delete hash lookup */ - bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0]; - bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1]; - bibe_key.fib_index = bibe->fib_index; - bibe_key.port = bibe->in_port; - bibe_key.proto = bibe->proto; - bibe_key.rsvd = 0; - kv.key[0] = bibe_key.as_u64[0]; - kv.key[1] = bibe_key.as_u64[1]; - kv.key[2] = bibe_key.as_u64[2]; - clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 0); - - memset (&bibe_key.addr, 0, sizeof (bibe_key.addr)); - bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32; - bibe_key.fib_index = 0; - bibe_key.port = bibe->out_port; - kv.key[0] = bibe_key.as_u64[0]; - kv.key[1] = bibe_key.as_u64[1]; - kv.key[2] = bibe_key.as_u64[2]; - clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 0); - - /* delete from pool */ - pool_put (bib, bibe); - -} - -nat64_db_bib_entry_t * -nat64_db_bib_entry_find (nat64_db_t * db, ip46_address_t * addr, u16 port, - u8 proto, u32 fib_index, u8 is_ip6) -{ - nat64_db_bib_entry_t *bibe = 0; - nat64_db_bib_entry_key_t bibe_key; - clib_bihash_kv_24_8_t kv, value; - nat64_db_bib_entry_t *bib; - - switch (ip_proto_to_snat_proto (proto)) - { -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - bib = db->bib._##n##_bib; \ - break; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - default: - bib = db->bib._unk_proto_bib; - break; - } - - bibe_key.addr.as_u64[0] = addr->as_u64[0]; - bibe_key.addr.as_u64[1] = addr->as_u64[1]; - bibe_key.fib_index = fib_index; - bibe_key.port = port; - bibe_key.proto = proto; - bibe_key.rsvd = 0; - - kv.key[0] = bibe_key.as_u64[0]; - kv.key[1] = bibe_key.as_u64[1]; - kv.key[2] = bibe_key.as_u64[2]; - - if (!clib_bihash_search_24_8 - (is_ip6 ? &db->bib.in2out : &db->bib.out2in, &kv, &value)) - bibe = pool_elt_at_index (bib, value.value); - - return bibe; -} - -void -nat64_db_bib_walk (nat64_db_t * db, u8 proto, - nat64_db_bib_walk_fn_t fn, void *ctx) -{ - nat64_db_bib_entry_t *bib, *bibe; - - if (proto == 255) - { - /* *INDENT-OFF* */ - #define _(N, i, n, s) \ - bib = db->bib._##n##_bib; \ - pool_foreach (bibe, bib, ({ \ - if (fn (bibe, ctx)) \ - return; \ - })); - foreach_snat_protocol - #undef _ - bib = db->bib._unk_proto_bib; - pool_foreach (bibe, bib, ({ - if (fn (bibe, ctx)) - return; - })); - /* *INDENT-ON* */ - } - else - { - switch (ip_proto_to_snat_proto (proto)) - { - /* *INDENT-OFF* */ - #define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - bib = db->bib._##n##_bib; \ - break; - foreach_snat_protocol - #undef _ - /* *INDENT-ON* */ - default: - bib = db->bib._unk_proto_bib; - break; - } - - /* *INDENT-OFF* */ - pool_foreach (bibe, bib, - ({ - if (fn (bibe, ctx)) - return; - })); - /* *INDENT-ON* */ - } -} - -nat64_db_bib_entry_t * -nat64_db_bib_entry_by_index (nat64_db_t * db, u8 proto, u32 bibe_index) -{ - nat64_db_bib_entry_t *bib; - - switch (ip_proto_to_snat_proto (proto)) - { -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - bib = db->bib._##n##_bib; \ - break; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - default: - bib = db->bib._unk_proto_bib; - break; - } - - return pool_elt_at_index (bib, bibe_index); -} - -void -nat64_db_st_walk (nat64_db_t * db, u8 proto, - nat64_db_st_walk_fn_t fn, void *ctx) -{ - nat64_db_st_entry_t *st, *ste; - - if (proto == 255) - { - /* *INDENT-OFF* */ - #define _(N, i, n, s) \ - st = db->st._##n##_st; \ - pool_foreach (ste, st, ({ \ - if (fn (ste, ctx)) \ - return; \ - })); - foreach_snat_protocol - #undef _ - st = db->st._unk_proto_st; - pool_foreach (ste, st, ({ - if (fn (ste, ctx)) - return; - })); - /* *INDENT-ON* */ - } - else - { - switch (ip_proto_to_snat_proto (proto)) - { - /* *INDENT-OFF* */ - #define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - st = db->st._##n##_st; \ - break; - foreach_snat_protocol - #undef _ - /* *INDENT-ON* */ - default: - st = db->st._unk_proto_st; - break; - } - - /* *INDENT-OFF* */ - pool_foreach (ste, st, - ({ - if (fn (ste, ctx)) - return; - })); - /* *INDENT-ON* */ - } -} - -nat64_db_st_entry_t * -nat64_db_st_entry_create (nat64_db_t * db, nat64_db_bib_entry_t * bibe, - ip6_address_t * in_r_addr, - ip4_address_t * out_r_addr, u16 r_port) -{ - nat64_db_st_entry_t *ste; - nat64_db_bib_entry_t *bib; - nat64_db_st_entry_key_t ste_key; - clib_bihash_kv_48_8_t kv; - - /* create pool entry */ - switch (ip_proto_to_snat_proto (bibe->proto)) - { -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - pool_get (db->st._##n##_st, ste); \ - kv.value = ste - db->st._##n##_st; \ - bib = db->bib._##n##_bib; \ - break; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - default: - pool_get (db->st._unk_proto_st, ste); - kv.value = ste - db->st._unk_proto_st; - bib = db->bib._unk_proto_bib; - break; - } - memset (ste, 0, sizeof (*ste)); - ste->in_r_addr.as_u64[0] = in_r_addr->as_u64[0]; - ste->in_r_addr.as_u64[1] = in_r_addr->as_u64[1]; - ste->out_r_addr.as_u32 = out_r_addr->as_u32; - ste->r_port = r_port; - ste->bibe_index = bibe - bib; - ste->proto = bibe->proto; - - /* increment session number for BIB entry */ - bibe->ses_num++; - - /* create hash lookup */ - memset (&ste_key, 0, sizeof (ste_key)); - ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0]; - ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1]; - ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0]; - ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1]; - ste_key.fib_index = bibe->fib_index; - ste_key.l_port = bibe->in_port; - ste_key.r_port = ste->r_port; - ste_key.proto = ste->proto; - kv.key[0] = ste_key.as_u64[0]; - kv.key[1] = ste_key.as_u64[1]; - kv.key[2] = ste_key.as_u64[2]; - kv.key[3] = ste_key.as_u64[3]; - kv.key[4] = ste_key.as_u64[4]; - kv.key[5] = ste_key.as_u64[5]; - clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 1); - - memset (&ste_key, 0, sizeof (ste_key)); - ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32; - ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32; - ste_key.l_port = bibe->out_port; - ste_key.r_port = ste->r_port; - ste_key.proto = ste->proto; - kv.key[0] = ste_key.as_u64[0]; - kv.key[1] = ste_key.as_u64[1]; - kv.key[2] = ste_key.as_u64[2]; - kv.key[3] = ste_key.as_u64[3]; - kv.key[4] = ste_key.as_u64[4]; - kv.key[5] = ste_key.as_u64[5]; - clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 1); - - return ste; -} - -void -nat64_db_st_entry_free (nat64_db_t * db, nat64_db_st_entry_t * ste) -{ - nat64_db_st_entry_t *st; - nat64_db_bib_entry_t *bib, *bibe; - nat64_db_st_entry_key_t ste_key; - clib_bihash_kv_48_8_t kv; - - switch (ip_proto_to_snat_proto (ste->proto)) - { -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - st = db->st._##n##_st; \ - bib = db->bib._##n##_bib; \ - break; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - default: - st = db->st._unk_proto_st; - bib = db->bib._unk_proto_bib; - break; - } - - bibe = pool_elt_at_index (bib, ste->bibe_index); - - /* delete hash lookup */ - memset (&ste_key, 0, sizeof (ste_key)); - ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0]; - ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1]; - ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0]; - ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1]; - ste_key.fib_index = bibe->fib_index; - ste_key.l_port = bibe->in_port; - ste_key.r_port = ste->r_port; - ste_key.proto = ste->proto; - kv.key[0] = ste_key.as_u64[0]; - kv.key[1] = ste_key.as_u64[1]; - kv.key[2] = ste_key.as_u64[2]; - kv.key[3] = ste_key.as_u64[3]; - kv.key[4] = ste_key.as_u64[4]; - kv.key[5] = ste_key.as_u64[5]; - clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 0); - - memset (&ste_key, 0, sizeof (ste_key)); - ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32; - ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32; - ste_key.l_port = bibe->out_port; - ste_key.r_port = ste->r_port; - ste_key.proto = ste->proto; - kv.key[0] = ste_key.as_u64[0]; - kv.key[1] = ste_key.as_u64[1]; - kv.key[2] = ste_key.as_u64[2]; - kv.key[3] = ste_key.as_u64[3]; - kv.key[4] = ste_key.as_u64[4]; - kv.key[5] = ste_key.as_u64[5]; - clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 0); - - /* delete from pool */ - pool_put (st, ste); - - /* decrement session number for BIB entry */ - bibe->ses_num--; - - /* delete BIB entry if last session and dynamic */ - if (!bibe->is_static && !bibe->ses_num) - nat64_db_bib_entry_free (db, bibe); -} - -nat64_db_st_entry_t * -nat64_db_st_entry_find (nat64_db_t * db, ip46_address_t * l_addr, - ip46_address_t * r_addr, u16 l_port, u16 r_port, - u8 proto, u32 fib_index, u8 is_ip6) -{ - nat64_db_st_entry_t *ste = 0; - nat64_db_st_entry_t *st; - nat64_db_st_entry_key_t ste_key; - clib_bihash_kv_48_8_t kv, value; - - switch (ip_proto_to_snat_proto (proto)) - { -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - st = db->st._##n##_st; \ - break; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - default: - st = db->st._unk_proto_st; - break; - } - - memset (&ste_key, 0, sizeof (ste_key)); - ste_key.l_addr.as_u64[0] = l_addr->as_u64[0]; - ste_key.l_addr.as_u64[1] = l_addr->as_u64[1]; - ste_key.r_addr.as_u64[0] = r_addr->as_u64[0]; - ste_key.r_addr.as_u64[1] = r_addr->as_u64[1]; - ste_key.fib_index = fib_index; - ste_key.l_port = l_port; - ste_key.r_port = r_port; - ste_key.proto = proto; - kv.key[0] = ste_key.as_u64[0]; - kv.key[1] = ste_key.as_u64[1]; - kv.key[2] = ste_key.as_u64[2]; - kv.key[3] = ste_key.as_u64[3]; - kv.key[4] = ste_key.as_u64[4]; - kv.key[5] = ste_key.as_u64[5]; - - if (!clib_bihash_search_48_8 - (is_ip6 ? &db->st.in2out : &db->st.out2in, &kv, &value)) - ste = pool_elt_at_index (st, value.value); - - return ste; -} - -void -nad64_db_st_free_expired (nat64_db_t * db, u32 now) -{ - u32 *ste_to_be_free = 0, *ste_index; - nat64_db_st_entry_t *st, *ste; - -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - st = db->st._##n##_st; \ - pool_foreach (ste, st, ({\ - if (i == SNAT_PROTOCOL_TCP && !ste->tcp_state) \ - continue; \ - if (ste->expire < now) \ - vec_add1 (ste_to_be_free, ste - st); \ - })); \ - vec_foreach (ste_index, ste_to_be_free) \ - nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \ - vec_free (ste_to_be_free); \ - ste_to_be_free = 0; - foreach_snat_protocol -#undef _ - st = db->st._unk_proto_st; - pool_foreach (ste, st, ({ - if (ste->expire < now) - vec_add1 (ste_to_be_free, ste - st); - })); - vec_foreach (ste_index, ste_to_be_free) - nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); - vec_free (ste_to_be_free); -/* *INDENT-ON* */ -} - -void -nat64_db_free_out_addr (nat64_db_t * db, ip4_address_t * out_addr) -{ - u32 *ste_to_be_free = 0, *ste_index; - nat64_db_st_entry_t *st, *ste; - nat64_db_bib_entry_t *bibe; - -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - st = db->st._##n##_st; \ - pool_foreach (ste, st, ({ \ - bibe = pool_elt_at_index (db->bib._##n##_bib, ste->bibe_index); \ - if (bibe->out_addr.as_u32 == out_addr->as_u32) \ - vec_add1 (ste_to_be_free, ste - st); \ - })); \ - vec_foreach (ste_index, ste_to_be_free) \ - nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \ - vec_free (ste_to_be_free); \ - ste_to_be_free = 0; - foreach_snat_protocol -#undef _ - st = db->st._unk_proto_st; - pool_foreach (ste, st, ({ - bibe = pool_elt_at_index (db->bib._unk_proto_bib, ste->bibe_index); - if (bibe->out_addr.as_u32 == out_addr->as_u32) - vec_add1 (ste_to_be_free, ste - st); - })); - vec_foreach (ste_index, ste_to_be_free) - nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); - vec_free (ste_to_be_free); -/* *INDENT-ON* */ -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/nat64_db.h b/src/plugins/snat/nat64_db.h deleted file mode 100644 index 1e2dcc930d8..00000000000 --- a/src/plugins/snat/nat64_db.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief NAT64 DB - */ -#ifndef __included_nat64_db_h__ -#define __included_nat64_db_h__ - -#include <vppinfra/bihash_24_8.h> -#include <vppinfra/bihash_48_8.h> -#include <snat/snat.h> - - -typedef struct -{ - union - { - struct - { - ip46_address_t addr; - u32 fib_index; - u16 port; - u8 proto; - u8 rsvd; - }; - u64 as_u64[3]; - }; -} nat64_db_bib_entry_key_t; - -/* *INDENT-OFF* */ -typedef CLIB_PACKED(struct -{ - ip6_address_t in_addr; - u16 in_port; - ip4_address_t out_addr; - u16 out_port; - u32 fib_index; - u32 ses_num; - u8 proto; - u8 is_static; -}) nat64_db_bib_entry_t; -/* *INDENT-ON* */ - -typedef struct -{ - /* BIBs */ -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - nat64_db_bib_entry_t *_##n##_bib; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - nat64_db_bib_entry_t *_unk_proto_bib; - - /* BIB lookup */ - clib_bihash_24_8_t in2out; - clib_bihash_24_8_t out2in; -} nat64_db_bib_t; - -typedef struct -{ - union - { - struct - { - ip46_address_t l_addr; - ip46_address_t r_addr; - u32 fib_index; - u16 l_port; - u16 r_port; - u8 proto; - u8 rsvd[7]; - }; - u64 as_u64[6]; - }; -} nat64_db_st_entry_key_t; - -/* *INDENT-OFF* */ -typedef CLIB_PACKED(struct -{ - ip6_address_t in_r_addr; - ip4_address_t out_r_addr; - u16 r_port; - u32 bibe_index; - u32 expire; - u8 proto; - u8 tcp_state; -}) nat64_db_st_entry_t; -/* *INDENT-ON* */ - -typedef struct -{ - /* session tables */ -/* *INDENT-OFF* */ -#define _(N, i, n, s) \ - nat64_db_st_entry_t *_##n##_st; - foreach_snat_protocol -#undef _ -/* *INDENT-ON* */ - nat64_db_st_entry_t *_unk_proto_st; - - /* session lookup */ - clib_bihash_48_8_t in2out; - clib_bihash_48_8_t out2in; -} nat64_db_st_t; - -typedef struct -{ - nat64_db_bib_t bib; - nat64_db_st_t st; -} nat64_db_t; - -/** - * @brief Initialize NAT64 DB. - * - * @param db NAT64 DB. - * - * @returns 0 on success, non-zero value otherwise. - */ -int nat64_db_init (nat64_db_t * db); - -/** - * @brief Create new NAT64 BIB entry. - * - * @param db NAT64 DB. - * @param in_addr Inside IPv6 address. - * @param out_addr Outside IPv4 address. - * @param in_port Inside port number. - * @param out_port Outside port number. - * @param fib_index FIB index. - * @param proto L4 protocol. - * @param is_static 1 if static, 0 if dynamic. - * - * @returns BIB entry on success, 0 otherwise. - */ -nat64_db_bib_entry_t *nat64_db_bib_entry_create (nat64_db_t * db, - ip6_address_t * in_addr, - ip4_address_t * out_addr, - u16 in_port, u16 out_port, - u32 fib_index, - u8 proto, u8 is_static); - -/** - * @brief Free NAT64 BIB entry. - * - * @param db NAT64 DB. - * @param bibe BIB entry. - */ -void nat64_db_bib_entry_free (nat64_db_t * db, nat64_db_bib_entry_t * bibe); - -/** - * @brief Call back function when walking NAT64 BIB, non-zero - * return value stop walk. - */ -typedef int (*nat64_db_bib_walk_fn_t) (nat64_db_bib_entry_t * bibe, - void *ctx); -/** - * @brief Walk NAT64 BIB. - * - * @param db NAT64 DB. - * @param proto BIB L4 protocol: - * - 255 all BIBs - * - 6 TCP BIB - * - 17 UDP BIB - * - 1/58 ICMP BIB - * - otherwise "unknown" protocol BIB - * @param fn The function to invoke on each entry visited. - * @param ctx A context passed in the visit function. - */ -void nat64_db_bib_walk (nat64_db_t * db, u8 proto, - nat64_db_bib_walk_fn_t fn, void *ctx); - -/** - * @brief Find NAT64 BIB entry. - * - * @param db NAT64 DB. - * @param addr IP address. - * @param port Port number. - * @param proto L4 protocol. - * @param fib_index FIB index. - * @param is_ip6 1 if find by IPv6 (inside) address, 0 by IPv4 (outside). - * - * @return BIB entry if found. - */ -nat64_db_bib_entry_t *nat64_db_bib_entry_find (nat64_db_t * db, - ip46_address_t * addr, - u16 port, - u8 proto, - u32 fib_index, u8 is_ip6); - -/** - * @brief Get BIB entry by index and protocol. - * - * @param db NAT64 DB. - * @param proto L4 protocol. - * @param bibe_index BIB entry index. - * - * @return BIB entry if found. - */ -nat64_db_bib_entry_t *nat64_db_bib_entry_by_index (nat64_db_t * db, - u8 proto, u32 bibe_index); -/** - * @brief Create new NAT64 session table entry. - * - * @param db NAT64 DB. - * @param bibe Corresponding BIB entry. - * @param in_r_addr Inside IPv6 address of the remote host. - * @param out_r_addr Outside IPv4 address of the remote host. - * @param r_port Remote host port number. - * - * @returns BIB entry on success, 0 otherwise. - */ -nat64_db_st_entry_t *nat64_db_st_entry_create (nat64_db_t * db, - nat64_db_bib_entry_t * bibe, - ip6_address_t * in_r_addr, - ip4_address_t * out_r_addr, - u16 r_port); - -/** - * @brief Free NAT64 session table entry. - * - * @param db NAT64 DB. - * @param ste Session table entry. - */ -void nat64_db_st_entry_free (nat64_db_t * db, nat64_db_st_entry_t * ste); - -/** - * @brief Find NAT64 session table entry. - * - * @param db NAT64 DB. - * @param l_addr Local host address. - * @param r_addr Remote host address. - * @param l_port Local host port number. - * @param r_port Remote host port number. - * @param proto L4 protocol. - * @param fib_index FIB index. - * @param is_ip6 1 if find by IPv6 (inside) address, 0 by IPv4 (outside). - * - * @return BIB entry if found. - */ -nat64_db_st_entry_t *nat64_db_st_entry_find (nat64_db_t * db, - ip46_address_t * l_addr, - ip46_address_t * r_addr, - u16 l_port, u16 r_port, - u8 proto, - u32 fib_index, u8 is_ip6); - -/** - * @brief Call back function when walking NAT64 session table, non-zero - * return value stop walk. - */ -typedef int (*nat64_db_st_walk_fn_t) (nat64_db_st_entry_t * ste, void *ctx); - -/** - * @brief Walk NAT64 session table. - * - * @param db NAT64 DB. - * @param proto L4 protocol: - * - 255 all session tables - * - 6 TCP session table - * - 17 UDP session table - * - 1/58 ICMP session table - * - otherwise "unknown" protocol session table - * @param fn The function to invoke on each entry visited. - * @param ctx A context passed in the visit function. - */ -void nat64_db_st_walk (nat64_db_t * db, u8 proto, - nat64_db_st_walk_fn_t fn, void *ctx); - -/** - * @brief Free expired session entries in session tables. - * - * @param db NAT64 DB. - * @param now Current time. - */ -void nad64_db_st_free_expired (nat64_db_t * db, u32 now); - -/** - * @brief Free sessions using specific outside address. - * - * @param db NAT64 DB. - * @param out_addr Outside address to match. - */ -void nat64_db_free_out_addr (nat64_db_t * db, ip4_address_t * out_addr); - -#endif /* __included_nat64_db_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/nat64_doc.md b/src/plugins/snat/nat64_doc.md deleted file mode 100644 index f94467dade1..00000000000 --- a/src/plugins/snat/nat64_doc.md +++ /dev/null @@ -1,73 +0,0 @@ -# Stateful NAT64: Network Address and Protocol Translation from IPv6 Clients to IPv4 Servers {#nat64_doc} - -## Introduction - -Stateful NAT64 in VPP allows IPv6-only clients to contact IPv4 servers using unicast UDP, TCP, or ICMP based on RFC 6146. - -## Configuration - -### Enable/disable NAT64 feature on the interface - -> set interface nat64 in|out <intfc> [del] - -in: inside/local/IPv6 network -out: outside/external/IPv4 network -intfc: interface name - -### Add/delete NAT64 pool address - -One or more public IPv4 addresses assigned to a NAT64 are shared among several IPv6-only clients. - -> nat64 add pool address <ip4-range-start> [- <ip4-range-end>] [tenant-vrf <tenant-vrf-id>] [del] - -ip4-range-start: First IPv4 address of the range -ip4-range-end: Last IPv4 address of the range (optional, not used for single address) -tenant-vrf-id: VRF id of the tenant associated with the pool address (optional, if not set pool address is global) - -### Add/delete static BIB entry - -Stateful NAT64 also supports IPv4-initiated communications to a subset of the IPv6 hosts through staticaly configured bindings. - -> nat64 add static bib <ip6-addr> <in-port> <ip4-addr> <out-port> tcp|udp|icmp [vfr <table-id>] [del] - -ip6-addr: inside IPv6 address of the host -in-port: inside port or ICMPv6 identifier -ip4-addr: outside IPv4 address of the host -out-port: outside port or ICMPv4 identifier -table-id: VRF id of the tenant associated with the BIB entry (optional, default use global VRF) - -### Set NAT64 session timeouts - -Session is deleted when timer expires. If all sessions corresponding to a dynamically create BIB entry are deleted, then the BIB entry is also deleted. When packets are flowing sessiom timer is refreshed to keep the session alive. - -> set nat64 timeouts udp <sec> icmp <sec> tcp-trans <sec> tcp-est <sec> tcp-incoming-syn <sec> | reset - -udp: UDP session timeout value (default 300sec) -icmp: ICMP session timeout value (default 60sec) -tcp-trans: transitory TCP session timeout value (default 240sec) -tcp-est: established TCP session timeout value (default 7440sec) -tcp-incoming-syn: incoming SYN TCP session timeout value (default 6sec) -reset: reset timers to default values - -### Set NAT64 prefix - -Stateful NAT64 support the algorithm for generating IPv6 representations of IPv4 addresses defined in RFC 6052. If no prefix is configured, Well-Known Prefix (64:ff9b::/96) is used. - -> nat64 add prefix <ip6-prefix>/<plen> [tenant-vrf <vrf-id>] [del] - -ip6-prefix: IPv6 prefix -plen: prefix length (valid values: 32, 40, 48, 56, 64, or 96) -tenant-vrf: VRF id of the tenant associated with the prefix - -### Show commands - -> show nat64 pool -> show nat64 interfaces -> show nat64 bib tcp|udp|icmp -> show nat64 session table tcp|udp|icmp -> show nat64 tiemouts -> show nat64 prefix - -## Notes - -Multi thread is not supported yet (CLI/API commands are disabled when VPP runs with multiple threads). diff --git a/src/plugins/snat/nat64_in2out.c b/src/plugins/snat/nat64_in2out.c deleted file mode 100644 index 8c67fec2b29..00000000000 --- a/src/plugins/snat/nat64_in2out.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief NAT64 IPv6 to IPv4 translation (inside to outside network) - */ - -#include <snat/nat64.h> -#include <vnet/ip/ip6_to_ip4.h> -#include <vnet/fib/fib_table.h> - -typedef struct -{ - u32 sw_if_index; - u32 next_index; - u8 is_slow_path; -} nat64_in2out_trace_t; - -static u8 * -format_nat64_in2out_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - nat64_in2out_trace_t *t = va_arg (*args, nat64_in2out_trace_t *); - char *tag; - - tag = t->is_slow_path ? "NAT64-in2out-slowpath" : "NAT64-in2out"; - - s = - format (s, "%s: sw_if_index %d, next index %d", tag, t->sw_if_index, - t->next_index); - - return s; -} - -vlib_node_registration_t nat64_in2out_node; -vlib_node_registration_t nat64_in2out_slowpath_node; - -#define foreach_nat64_in2out_error \ -_(UNSUPPORTED_PROTOCOL, "unsupported protocol") \ -_(IN2OUT_PACKETS, "good in2out packets processed") \ -_(NO_TRANSLATION, "no translation") \ -_(UNKNOWN, "unknown") - -typedef enum -{ -#define _(sym,str) NAT64_IN2OUT_ERROR_##sym, - foreach_nat64_in2out_error -#undef _ - NAT64_IN2OUT_N_ERROR, -} nat64_in2out_error_t; - -static char *nat64_in2out_error_strings[] = { -#define _(sym,string) string, - foreach_nat64_in2out_error -#undef _ -}; - -typedef enum -{ - NAT64_IN2OUT_NEXT_IP4_LOOKUP, - NAT64_IN2OUT_NEXT_IP6_LOOKUP, - NAT64_IN2OUT_NEXT_DROP, - NAT64_IN2OUT_NEXT_SLOWPATH, - NAT64_IN2OUT_N_NEXT, -} nat64_in2out_next_t; - -typedef struct nat64_in2out_set_ctx_t_ -{ - vlib_buffer_t *b; - vlib_main_t *vm; -} nat64_in2out_set_ctx_t; - -/** - * @brief Check whether is a hairpinning. - * - * If the destination IP address of the packet is an IPv4 address assigned to - * the NAT64 itself, then the packet is a hairpin packet. - * - * param dst_addr Destination address of the packet. - * - * @returns 1 if hairpinning, otherwise 0. - */ -static_always_inline int -is_hairpinning (ip6_address_t * dst_addr) -{ - nat64_main_t *nm = &nat64_main; - int i; - - for (i = 0; i < vec_len (nm->addr_pool); i++) - { - if (nm->addr_pool[i].addr.as_u32 == dst_addr->as_u32[3]) - return 1; - } - - return 0; -} - -static int -nat64_in2out_tcp_udp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, - void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_in2out_set_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr; - u32 sw_if_index, fib_index; - udp_header_t *udp = ip6_next_header (ip6); - u8 proto = ip6->protocol; - u16 sport = udp->src_port; - u16 dport = udp->dst_port; - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - saddr.as_u64[0] = ip6->src_address.as_u64[0]; - saddr.as_u64[1] = ip6->src_address.as_u64[1]; - daddr.as_u64[0] = ip6->dst_address.as_u64[0]; - daddr.as_u64[1] = ip6->dst_address.as_u64[1]; - - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto, - fib_index, 1); - - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &saddr, sport, proto, fib_index, 1); - - if (!bibe) - { - u16 out_port; - ip4_address_t out_addr; - if (nat64_alloc_out_addr_and_port - (fib_index, ip_proto_to_snat_proto (proto), &out_addr, - &out_port)) - return -1; - - bibe = - nat64_db_bib_entry_create (&nm->db, &ip6->src_address, &out_addr, - sport, clib_host_to_net_u16 (out_port), - fib_index, proto, 0); - if (!bibe) - return -1; - } - - nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address, - &daddr.ip4, dport); - if (!ste) - return -1; - } - - nat64_session_reset_timeout (ste, ctx->vm); - - ip4->src_address.as_u32 = bibe->out_addr.as_u32; - udp->src_port = bibe->out_port; - - ip4->dst_address.as_u32 = ste->out_r_addr.as_u32; - - if (proto == IP_PROTOCOL_TCP) - { - u16 *checksum; - ip_csum_t csum; - tcp_header_t *tcp = ip6_next_header (ip6); - - checksum = &tcp->checksum; - csum = ip_csum_sub_even (*checksum, sport); - csum = ip_csum_add_even (csum, udp->src_port); - *checksum = ip_csum_fold (csum); - } - - return 0; -} - -static int -nat64_in2out_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_in2out_set_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr; - u32 sw_if_index, fib_index; - icmp46_header_t *icmp = ip6_next_header (ip6); - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - saddr.as_u64[0] = ip6->src_address.as_u64[0]; - saddr.as_u64[1] = ip6->src_address.as_u64[1]; - daddr.as_u64[0] = ip6->dst_address.as_u64[0]; - daddr.as_u64[1] = ip6->dst_address.as_u64[1]; - - if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply) - { - u16 in_id = ((u16 *) (icmp))[2]; - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, in_id, 0, - IP_PROTOCOL_ICMP, fib_index, 1); - - if (ste) - { - bibe = - nat64_db_bib_entry_by_index (&nm->db, IP_PROTOCOL_ICMP, - ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &saddr, in_id, - IP_PROTOCOL_ICMP, fib_index, 1); - - if (!bibe) - { - u16 out_id; - ip4_address_t out_addr; - if (nat64_alloc_out_addr_and_port - (fib_index, SNAT_PROTOCOL_ICMP, &out_addr, &out_id)) - return -1; - - bibe = - nat64_db_bib_entry_create (&nm->db, &ip6->src_address, - &out_addr, in_id, - clib_host_to_net_u16 (out_id), - fib_index, IP_PROTOCOL_ICMP, 0); - if (!bibe) - return -1; - } - - nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address, - &daddr.ip4, 0); - if (!ste) - return -1; - } - - nat64_session_reset_timeout (ste, ctx->vm); - - ip4->src_address.as_u32 = bibe->out_addr.as_u32; - ((u16 *) (icmp))[2] = bibe->out_port; - - ip4->dst_address.as_u32 = ste->out_r_addr.as_u32; - } - else - { - if (!vec_len (nm->addr_pool)) - return -1; - - ip4->src_address.as_u32 = nm->addr_pool[0].addr.as_u32; - nat64_extract_ip4 (&ip6->dst_address, &ip4->dst_address, fib_index); - } - - return 0; -} - -static int -nat64_in2out_inner_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, - void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_in2out_set_ctx_t *ctx = arg; - nat64_db_st_entry_t *ste; - nat64_db_bib_entry_t *bibe; - ip46_address_t saddr, daddr; - u32 sw_if_index, fib_index; - u8 proto = ip6->protocol; - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - saddr.as_u64[0] = ip6->src_address.as_u64[0]; - saddr.as_u64[1] = ip6->src_address.as_u64[1]; - daddr.as_u64[0] = ip6->dst_address.as_u64[0]; - daddr.as_u64[1] = ip6->dst_address.as_u64[1]; - - if (proto == IP_PROTOCOL_ICMP6) - { - icmp46_header_t *icmp = ip6_next_header (ip6); - u16 in_id = ((u16 *) (icmp))[2]; - proto = IP_PROTOCOL_ICMP; - - if (! - (icmp->type == ICMP4_echo_request - || icmp->type == ICMP4_echo_reply)) - return -1; - - ste = - nat64_db_st_entry_find (&nm->db, &daddr, &saddr, in_id, 0, proto, - fib_index, 1); - if (!ste) - return -1; - - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - - ip4->dst_address.as_u32 = bibe->out_addr.as_u32; - ((u16 *) (icmp))[2] = bibe->out_port; - ip4->src_address.as_u32 = ste->out_r_addr.as_u32; - } - else - { - udp_header_t *udp = ip6_next_header (ip6); - tcp_header_t *tcp = ip6_next_header (ip6); - u16 *checksum; - ip_csum_t csum; - - u16 sport = udp->src_port; - u16 dport = udp->dst_port; - - ste = - nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto, - fib_index, 1); - if (!ste) - return -1; - - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - - ip4->dst_address.as_u32 = bibe->out_addr.as_u32; - udp->dst_port = bibe->out_port; - ip4->src_address.as_u32 = ste->out_r_addr.as_u32; - - if (proto == IP_PROTOCOL_TCP) - checksum = &tcp->checksum; - else - checksum = &udp->checksum; - csum = ip_csum_sub_even (*checksum, dport); - csum = ip_csum_add_even (csum, udp->dst_port); - *checksum = ip_csum_fold (csum); - } - - return 0; -} - -typedef struct unk_proto_st_walk_ctx_t_ -{ - ip6_address_t src_addr; - ip6_address_t dst_addr; - ip4_address_t out_addr; - u32 fib_index; - u8 proto; -} unk_proto_st_walk_ctx_t; - -static int -unk_proto_st_walk (nat64_db_st_entry_t * ste, void *arg) -{ - nat64_main_t *nm = &nat64_main; - unk_proto_st_walk_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - ip46_address_t saddr, daddr; - - if (ip46_address_is_equal (&ste->in_r_addr, &ctx->dst_addr)) - { - bibe = - nat64_db_bib_entry_by_index (&nm->db, ste->proto, ste->bibe_index); - if (!bibe) - return -1; - - if (ip46_address_is_equal (&bibe->in_addr, &ctx->src_addr) - && bibe->fib_index == ctx->fib_index) - { - memset (&saddr, 0, sizeof (saddr)); - saddr.ip4.as_u32 = bibe->out_addr.as_u32; - memset (&daddr, 0, sizeof (daddr)); - nat64_extract_ip4 (&ctx->dst_addr, &daddr.ip4, ctx->fib_index); - - if (nat64_db_st_entry_find - (&nm->db, &daddr, &saddr, 0, 0, ctx->proto, ctx->fib_index, 0)) - return -1; - - ctx->out_addr.as_u32 = bibe->out_addr.as_u32; - return 1; - } - } - - return 0; -} - -static int -nat64_in2out_unk_proto_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, - void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_in2out_set_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr, addr; - u32 sw_if_index, fib_index; - u8 proto = ip6->protocol; - int i; - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - saddr.as_u64[0] = ip6->src_address.as_u64[0]; - saddr.as_u64[1] = ip6->src_address.as_u64[1]; - daddr.as_u64[0] = ip6->dst_address.as_u64[0]; - daddr.as_u64[1] = ip6->dst_address.as_u64[1]; - - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, 0, 0, proto, fib_index, - 1); - - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &saddr, 0, proto, fib_index, 1); - - if (!bibe) - { - /* Choose same out address as for TCP/UDP session to same dst */ - unk_proto_st_walk_ctx_t ctx = { - .src_addr.as_u64[0] = ip6->src_address.as_u64[0], - .src_addr.as_u64[1] = ip6->src_address.as_u64[1], - .dst_addr.as_u64[0] = ip6->dst_address.as_u64[0], - .dst_addr.as_u64[1] = ip6->dst_address.as_u64[1], - .out_addr.as_u32 = 0, - .fib_index = fib_index, - .proto = proto, - }; - - nat64_db_st_walk (&nm->db, IP_PROTOCOL_TCP, unk_proto_st_walk, - &ctx); - - if (!ctx.out_addr.as_u32) - nat64_db_st_walk (&nm->db, IP_PROTOCOL_UDP, unk_proto_st_walk, - &ctx); - - /* Verify if out address is not already in use for protocol */ - memset (&addr, 0, sizeof (addr)); - addr.ip4.as_u32 = ctx.out_addr.as_u32; - if (nat64_db_bib_entry_find (&nm->db, &addr, 0, proto, 0, 0)) - ctx.out_addr.as_u32 = 0; - - if (!ctx.out_addr.as_u32) - { - for (i = 0; i < vec_len (nm->addr_pool); i++) - { - addr.ip4.as_u32 = nm->addr_pool[i].addr.as_u32; - if (!nat64_db_bib_entry_find - (&nm->db, &addr, 0, proto, 0, 0)) - break; - } - } - - if (!ctx.out_addr.as_u32) - return -1; - - bibe = - nat64_db_bib_entry_create (&nm->db, &ip6->src_address, - &ctx.out_addr, 0, 0, fib_index, proto, - 0); - if (!bibe) - return -1; - } - - nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address, - &daddr.ip4, 0); - if (!ste) - return -1; - } - - nat64_session_reset_timeout (ste, ctx->vm); - - ip4->src_address.as_u32 = bibe->out_addr.as_u32; - ip4->dst_address.as_u32 = ste->out_r_addr.as_u32; - - return 0; -} - - - -static int -nat64_in2out_tcp_udp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, - ip6_header_t * ip6) -{ - nat64_main_t *nm = &nat64_main; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr; - u32 sw_if_index, fib_index; - udp_header_t *udp = ip6_next_header (ip6); - tcp_header_t *tcp = ip6_next_header (ip6); - u8 proto = ip6->protocol; - u16 sport = udp->src_port; - u16 dport = udp->dst_port; - u16 *checksum; - ip_csum_t csum; - - sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - saddr.as_u64[0] = ip6->src_address.as_u64[0]; - saddr.as_u64[1] = ip6->src_address.as_u64[1]; - daddr.as_u64[0] = ip6->dst_address.as_u64[0]; - daddr.as_u64[1] = ip6->dst_address.as_u64[1]; - - if (proto == IP_PROTOCOL_UDP) - checksum = &udp->checksum; - else - checksum = &tcp->checksum; - - csum = ip_csum_sub_even (*checksum, ip6->src_address.as_u64[0]); - csum = ip_csum_sub_even (csum, ip6->src_address.as_u64[1]); - csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[0]); - csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[1]); - csum = ip_csum_sub_even (csum, sport); - csum = ip_csum_sub_even (csum, dport); - - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto, - fib_index, 1); - - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &saddr, sport, proto, fib_index, 1); - - if (!bibe) - { - u16 out_port; - ip4_address_t out_addr; - if (nat64_alloc_out_addr_and_port - (fib_index, ip_proto_to_snat_proto (proto), &out_addr, - &out_port)) - return -1; - - bibe = - nat64_db_bib_entry_create (&nm->db, &ip6->src_address, &out_addr, - sport, clib_host_to_net_u16 (out_port), - fib_index, proto, 0); - if (!bibe) - return -1; - } - - nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address, - &daddr.ip4, dport); - if (!ste) - return -1; - } - - nat64_session_reset_timeout (ste, vm); - - sport = udp->src_port = bibe->out_port; - nat64_compose_ip6 (&ip6->src_address, &bibe->out_addr, fib_index); - - memset (&saddr, 0, sizeof (saddr)); - memset (&daddr, 0, sizeof (daddr)); - saddr.ip4.as_u32 = bibe->out_addr.as_u32; - daddr.ip4.as_u32 = ste->out_r_addr.as_u32; - - ste = - nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto, 0, - 0); - - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = nat64_db_bib_entry_find (&nm->db, &daddr, dport, proto, 0, 0); - - if (!bibe) - return -1; - - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6->src_address, - &saddr.ip4, sport); - } - - ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0]; - ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1]; - udp->dst_port = bibe->in_port; - - csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]); - csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]); - csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]); - csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]); - csum = ip_csum_add_even (csum, udp->src_port); - csum = ip_csum_add_even (csum, udp->dst_port); - *checksum = ip_csum_fold (csum); - - return 0; -} - -static int -nat64_in2out_icmp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, - ip6_header_t * ip6) -{ - nat64_main_t *nm = &nat64_main; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - icmp46_header_t *icmp = ip6_next_header (ip6); - ip6_header_t *inner_ip6; - ip46_address_t saddr, daddr; - u32 sw_if_index, fib_index; - u8 proto; - udp_header_t *udp; - tcp_header_t *tcp; - u16 *checksum, sport, dport; - ip_csum_t csum; - - if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply) - return -1; - - inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8); - - proto = inner_ip6->protocol; - - if (proto == IP_PROTOCOL_ICMP6) - return -1; - - sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - saddr.as_u64[0] = inner_ip6->src_address.as_u64[0]; - saddr.as_u64[1] = inner_ip6->src_address.as_u64[1]; - daddr.as_u64[0] = inner_ip6->dst_address.as_u64[0]; - daddr.as_u64[1] = inner_ip6->dst_address.as_u64[1]; - - udp = ip6_next_header (inner_ip6); - tcp = ip6_next_header (inner_ip6); - - sport = udp->src_port; - dport = udp->dst_port; - - if (proto == IP_PROTOCOL_UDP) - checksum = &udp->checksum; - else - checksum = &tcp->checksum; - - csum = ip_csum_sub_even (*checksum, inner_ip6->src_address.as_u64[0]); - csum = ip_csum_sub_even (csum, inner_ip6->src_address.as_u64[1]); - csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[0]); - csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[1]); - csum = ip_csum_sub_even (csum, sport); - csum = ip_csum_sub_even (csum, dport); - - ste = - nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto, - fib_index, 1); - if (!ste) - return -1; - - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - - dport = udp->dst_port = bibe->out_port; - nat64_compose_ip6 (&inner_ip6->dst_address, &bibe->out_addr, fib_index); - - memset (&saddr, 0, sizeof (saddr)); - memset (&daddr, 0, sizeof (daddr)); - saddr.ip4.as_u32 = ste->out_r_addr.as_u32; - daddr.ip4.as_u32 = bibe->out_addr.as_u32; - - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto, 0, - 0); - if (!ste) - return -1; - - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - - inner_ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0]; - inner_ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1]; - udp->src_port = bibe->in_port; - - csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[0]); - csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[1]); - csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[0]); - csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[1]); - csum = ip_csum_add_even (csum, udp->src_port); - csum = ip_csum_add_even (csum, udp->dst_port); - *checksum = ip_csum_fold (csum); - - if (!vec_len (nm->addr_pool)) - return -1; - - nat64_compose_ip6 (&ip6->src_address, &nm->addr_pool[0].addr, fib_index); - ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0]; - ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1]; - - icmp->checksum = 0; - csum = ip_csum_with_carry (0, ip6->payload_length); - csum = ip_csum_with_carry (csum, clib_host_to_net_u16 (ip6->protocol)); - csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[0]); - csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[1]); - csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[0]); - csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[1]); - csum = - ip_incremental_checksum (csum, icmp, - clib_net_to_host_u16 (ip6->payload_length)); - icmp->checksum = ~ip_csum_fold (csum); - - return 0; -} - -static int -nat64_in2out_unk_proto_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, - ip6_header_t * ip6) -{ - nat64_main_t *nm = &nat64_main; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr, addr; - u32 sw_if_index, fib_index; - u8 proto = ip6->protocol; - int i; - - sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - saddr.as_u64[0] = ip6->src_address.as_u64[0]; - saddr.as_u64[1] = ip6->src_address.as_u64[1]; - daddr.as_u64[0] = ip6->dst_address.as_u64[0]; - daddr.as_u64[1] = ip6->dst_address.as_u64[1]; - - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, 0, 0, proto, fib_index, - 1); - - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &saddr, 0, proto, fib_index, 1); - - if (!bibe) - { - /* Choose same out address as for TCP/UDP session to same dst */ - unk_proto_st_walk_ctx_t ctx = { - .src_addr.as_u64[0] = ip6->src_address.as_u64[0], - .src_addr.as_u64[1] = ip6->src_address.as_u64[1], - .dst_addr.as_u64[0] = ip6->dst_address.as_u64[0], - .dst_addr.as_u64[1] = ip6->dst_address.as_u64[1], - .out_addr.as_u32 = 0, - .fib_index = fib_index, - .proto = proto, - }; - - nat64_db_st_walk (&nm->db, IP_PROTOCOL_TCP, unk_proto_st_walk, - &ctx); - - if (!ctx.out_addr.as_u32) - nat64_db_st_walk (&nm->db, IP_PROTOCOL_UDP, unk_proto_st_walk, - &ctx); - - /* Verify if out address is not already in use for protocol */ - memset (&addr, 0, sizeof (addr)); - addr.ip4.as_u32 = ctx.out_addr.as_u32; - if (nat64_db_bib_entry_find (&nm->db, &addr, 0, proto, 0, 0)) - ctx.out_addr.as_u32 = 0; - - if (!ctx.out_addr.as_u32) - { - for (i = 0; i < vec_len (nm->addr_pool); i++) - { - addr.ip4.as_u32 = nm->addr_pool[i].addr.as_u32; - if (!nat64_db_bib_entry_find - (&nm->db, &addr, 0, proto, 0, 0)) - break; - } - } - - if (!ctx.out_addr.as_u32) - return -1; - - bibe = - nat64_db_bib_entry_create (&nm->db, &ip6->src_address, - &ctx.out_addr, 0, 0, fib_index, proto, - 0); - if (!bibe) - return -1; - } - - nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address, - &daddr.ip4, 0); - if (!ste) - return -1; - } - - nat64_session_reset_timeout (ste, vm); - - nat64_compose_ip6 (&ip6->src_address, &bibe->out_addr, fib_index); - - memset (&saddr, 0, sizeof (saddr)); - memset (&daddr, 0, sizeof (daddr)); - saddr.ip4.as_u32 = bibe->out_addr.as_u32; - daddr.ip4.as_u32 = ste->out_r_addr.as_u32; - - ste = nat64_db_st_entry_find (&nm->db, &daddr, &saddr, 0, 0, proto, 0, 0); - - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = nat64_db_bib_entry_find (&nm->db, &daddr, 0, proto, 0, 0); - - if (!bibe) - return -1; - - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6->src_address, - &saddr.ip4, 0); - } - - ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0]; - ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1]; - - return 0; -} - -static inline uword -nat64_in2out_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, u8 is_slow_path) -{ - u32 n_left_from, *from, *to_next; - nat64_in2out_next_t next_index; - u32 pkts_processed = 0; - u32 stats_node_index; - - stats_node_index = - is_slow_path ? nat64_in2out_slowpath_node.index : nat64_in2out_node.index; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0; - ip6_header_t *ip60; - u16 l4_offset0, frag_offset0; - u8 l4_protocol0; - u32 proto0; - nat64_in2out_set_ctx_t ctx0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip60 = vlib_buffer_get_current (b0); - - ctx0.b = b0; - ctx0.vm = vm; - - next0 = NAT64_IN2OUT_NEXT_IP4_LOOKUP; - - if (PREDICT_FALSE - (ip6_parse - (ip60, b0->current_length, &l4_protocol0, &l4_offset0, - &frag_offset0))) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = node->errors[NAT64_IN2OUT_ERROR_UNKNOWN]; - goto trace0; - } - - proto0 = ip_proto_to_snat_proto (l4_protocol0); - if (frag_offset0 != 0) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = - node->errors[NAT64_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL]; - goto trace0; - } - - if (is_slow_path) - { - if (PREDICT_TRUE (proto0 == ~0)) - { - if (is_hairpinning (&ip60->dst_address)) - { - next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP; - if (nat64_in2out_unk_proto_hairpinning (vm, b0, ip60)) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = - node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION]; - } - goto trace0; - } - - if (ip6_to_ip4 (b0, nat64_in2out_unk_proto_set_cb, &ctx0)) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = - node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION]; - goto trace0; - } - } - goto trace0; - } - else - { - if (PREDICT_FALSE (proto0 == ~0)) - { - next0 = NAT64_IN2OUT_NEXT_SLOWPATH; - goto trace0; - } - } - - if (proto0 == SNAT_PROTOCOL_ICMP) - { - if (is_hairpinning (&ip60->dst_address)) - { - next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP; - if (nat64_in2out_icmp_hairpinning (vm, b0, ip60)) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = - node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION]; - } - goto trace0; - } - - if (icmp6_to_icmp - (b0, nat64_in2out_icmp_set_cb, &ctx0, - nat64_in2out_inner_icmp_set_cb, &ctx0)) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION]; - goto trace0; - } - } - else if (proto0 == SNAT_PROTOCOL_TCP || proto0 == SNAT_PROTOCOL_UDP) - { - if (is_hairpinning (&ip60->dst_address)) - { - next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP; - if (nat64_in2out_tcp_udp_hairpinning (vm, b0, ip60)) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = - node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION]; - } - goto trace0; - } - - if (ip6_to_ip4_tcp_udp - (b0, nat64_in2out_tcp_udp_set_cb, &ctx0, 0)) - { - next0 = NAT64_IN2OUT_NEXT_DROP; - b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION]; - goto trace0; - } - } - - trace0: - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - nat64_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->next_index = next0; - t->is_slow_path = is_slow_path; - } - - pkts_processed += next0 != NAT64_IN2OUT_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - vlib_node_increment_counter (vm, stats_node_index, - NAT64_IN2OUT_ERROR_IN2OUT_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -static uword -nat64_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return nat64_in2out_node_fn_inline (vm, node, frame, 0); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (nat64_in2out_node) = { - .function = nat64_in2out_node_fn, - .name = "nat64-in2out", - .vector_size = sizeof (u32), - .format_trace = format_nat64_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (nat64_in2out_error_strings), - .error_strings = nat64_in2out_error_strings, - .n_next_nodes = NAT64_IN2OUT_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = { - [NAT64_IN2OUT_NEXT_DROP] = "error-drop", - [NAT64_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup", - [NAT64_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup", - [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath", - }, -}; -/* *INDENT-ON* */ - -VLIB_NODE_FUNCTION_MULTIARCH (nat64_in2out_node, nat64_in2out_node_fn); - -static uword -nat64_in2out_slowpath_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - return nat64_in2out_node_fn_inline (vm, node, frame, 1); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (nat64_in2out_slowpath_node) = { - .function = nat64_in2out_slowpath_node_fn, - .name = "nat64-in2out-slowpath", - .vector_size = sizeof (u32), - .format_trace = format_nat64_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (nat64_in2out_error_strings), - .error_strings = nat64_in2out_error_strings, - .n_next_nodes = NAT64_IN2OUT_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = { - [NAT64_IN2OUT_NEXT_DROP] = "error-drop", - [NAT64_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup", - [NAT64_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup", - [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath", - }, -}; -/* *INDENT-ON* */ - -VLIB_NODE_FUNCTION_MULTIARCH (nat64_in2out_slowpath_node, - nat64_in2out_slowpath_node_fn); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/nat64_out2in.c b/src/plugins/snat/nat64_out2in.c deleted file mode 100644 index cd5b253ab5c..00000000000 --- a/src/plugins/snat/nat64_out2in.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief NAT64 IPv4 to IPv6 translation (otside to inside network) - */ - -#include <snat/nat64.h> -#include <vnet/ip/ip4_to_ip6.h> -#include <vnet/fib/ip4_fib.h> - -typedef struct -{ - u32 sw_if_index; - u32 next_index; -} nat64_out2in_trace_t; - -static u8 * -format_nat64_out2in_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - nat64_out2in_trace_t *t = va_arg (*args, nat64_out2in_trace_t *); - - s = - format (s, "NAT64-out2in: sw_if_index %d, next index %d", t->sw_if_index, - t->next_index); - - return s; -} - -vlib_node_registration_t nat64_out2in_node; - -#define foreach_nat64_out2in_error \ -_(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ -_(OUT2IN_PACKETS, "Good out2in packets processed") \ -_(NO_TRANSLATION, "No translation") \ -_(UNKNOWN, "unknown") - -typedef enum -{ -#define _(sym,str) NAT64_OUT2IN_ERROR_##sym, - foreach_nat64_out2in_error -#undef _ - NAT64_OUT2IN_N_ERROR, -} nat64_out2in_error_t; - -static char *nat64_out2in_error_strings[] = { -#define _(sym,string) string, - foreach_nat64_out2in_error -#undef _ -}; - -typedef enum -{ - NAT64_OUT2IN_NEXT_LOOKUP, - NAT64_OUT2IN_NEXT_DROP, - NAT64_OUT2IN_N_NEXT, -} nat64_out2in_next_t; - -typedef struct nat64_out2in_set_ctx_t_ -{ - vlib_buffer_t *b; - vlib_main_t *vm; -} nat64_out2in_set_ctx_t; - -static int -nat64_out2in_tcp_udp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, - void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_out2in_set_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr; - ip6_address_t ip6_saddr; - udp_header_t *udp = ip4_next_header (ip4); - tcp_header_t *tcp = ip4_next_header (ip4); - u8 proto = ip4->protocol; - u16 dport = udp->dst_port; - u16 sport = udp->src_port; - u32 sw_if_index, fib_index; - u16 *checksum; - ip_csum_t csum; - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); - - memset (&saddr, 0, sizeof (saddr)); - saddr.ip4.as_u32 = ip4->src_address.as_u32; - memset (&daddr, 0, sizeof (daddr)); - daddr.ip4.as_u32 = ip4->dst_address.as_u32; - - ste = - nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto, - fib_index, 0); - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &daddr, dport, proto, fib_index, 0); - - if (!bibe) - return -1; - - nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6_saddr, &saddr.ip4, - sport); - } - - nat64_session_reset_timeout (ste, ctx->vm); - - ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0]; - ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1]; - - ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0]; - ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1]; - udp->dst_port = bibe->in_port; - - if (proto == IP_PROTOCOL_UDP) - checksum = &udp->checksum; - else - checksum = &tcp->checksum; - csum = ip_csum_sub_even (*checksum, dport); - csum = ip_csum_add_even (csum, udp->dst_port); - *checksum = ip_csum_fold (csum); - - vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index; - - return 0; -} - -static int -nat64_out2in_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_out2in_set_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr; - ip6_address_t ip6_saddr; - u32 sw_if_index, fib_index; - icmp46_header_t *icmp = ip4_next_header (ip4); - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); - - memset (&saddr, 0, sizeof (saddr)); - saddr.ip4.as_u32 = ip4->src_address.as_u32; - memset (&daddr, 0, sizeof (daddr)); - daddr.ip4.as_u32 = ip4->dst_address.as_u32; - - if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply) - { - u16 out_id = ((u16 *) (icmp))[2]; - ste = - nat64_db_st_entry_find (&nm->db, &daddr, &saddr, out_id, 0, - IP_PROTOCOL_ICMP, fib_index, 0); - - if (ste) - { - bibe = - nat64_db_bib_entry_by_index (&nm->db, IP_PROTOCOL_ICMP, - ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &daddr, out_id, - IP_PROTOCOL_ICMP, fib_index, 0); - if (!bibe) - return -1; - - nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6_saddr, &saddr.ip4, - 0); - } - - nat64_session_reset_timeout (ste, ctx->vm); - - ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0]; - ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1]; - - ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0]; - ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1]; - ((u16 *) (icmp))[2] = bibe->in_port; - - vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index; - } - else - { - ip6_header_t *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8); - - nat64_compose_ip6 (&ip6->src_address, &ip4->src_address, - vnet_buffer (ctx->b)->sw_if_index[VLIB_TX]); - ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0]; - ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1]; - } - - return 0; -} - -static int -nat64_out2in_inner_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, - void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_out2in_set_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr; - u32 sw_if_index, fib_index; - u8 proto = ip4->protocol; - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index); - - memset (&saddr, 0, sizeof (saddr)); - saddr.ip4.as_u32 = ip4->src_address.as_u32; - memset (&daddr, 0, sizeof (daddr)); - daddr.ip4.as_u32 = ip4->dst_address.as_u32; - - if (proto == IP_PROTOCOL_ICMP6) - { - icmp46_header_t *icmp = ip4_next_header (ip4); - u16 out_id = ((u16 *) (icmp))[2]; - proto = IP_PROTOCOL_ICMP; - - if (! - (icmp->type == ICMP6_echo_request - || icmp->type == ICMP6_echo_reply)) - return -1; - - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, out_id, 0, proto, - fib_index, 0); - if (!ste) - return -1; - - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - - ip6->dst_address.as_u64[0] = ste->in_r_addr.as_u64[0]; - ip6->dst_address.as_u64[1] = ste->in_r_addr.as_u64[1]; - ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0]; - ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1]; - ((u16 *) (icmp))[2] = bibe->in_port; - - vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index; - } - else - { - udp_header_t *udp = ip4_next_header (ip4); - tcp_header_t *tcp = ip4_next_header (ip4); - u16 dport = udp->dst_port; - u16 sport = udp->src_port; - u16 *checksum; - ip_csum_t csum; - - ste = - nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto, - fib_index, 0); - if (!ste) - return -1; - - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - - nat64_compose_ip6 (&ip6->dst_address, &daddr.ip4, bibe->fib_index); - ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0]; - ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1]; - udp->src_port = bibe->in_port; - - if (proto == IP_PROTOCOL_UDP) - checksum = &udp->checksum; - else - checksum = &tcp->checksum; - if (*checksum) - { - csum = ip_csum_sub_even (*checksum, sport); - csum = ip_csum_add_even (csum, udp->src_port); - *checksum = ip_csum_fold (csum); - } - - vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index; - } - - return 0; -} - -static int -nat64_out2in_unk_proto_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, - void *arg) -{ - nat64_main_t *nm = &nat64_main; - nat64_out2in_set_ctx_t *ctx = arg; - nat64_db_bib_entry_t *bibe; - nat64_db_st_entry_t *ste; - ip46_address_t saddr, daddr; - ip6_address_t ip6_saddr; - u32 sw_if_index, fib_index; - u8 proto = ip4->protocol; - - sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX]; - fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); - - memset (&saddr, 0, sizeof (saddr)); - saddr.ip4.as_u32 = ip4->src_address.as_u32; - memset (&daddr, 0, sizeof (daddr)); - daddr.ip4.as_u32 = ip4->dst_address.as_u32; - - ste = - nat64_db_st_entry_find (&nm->db, &daddr, &saddr, 0, 0, proto, fib_index, - 0); - if (ste) - { - bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index); - if (!bibe) - return -1; - } - else - { - bibe = - nat64_db_bib_entry_find (&nm->db, &daddr, 0, proto, fib_index, 0); - - if (!bibe) - return -1; - - nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index); - ste = - nat64_db_st_entry_create (&nm->db, bibe, &ip6_saddr, &saddr.ip4, 0); - } - - nat64_session_reset_timeout (ste, ctx->vm); - - ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0]; - ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1]; - - ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0]; - ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1]; - - vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index; - - return 0; -} - -static uword -nat64_out2in_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - nat64_out2in_next_t next_index; - u32 pkts_processed = 0; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0; - ip4_header_t *ip40; - u32 proto0; - nat64_out2in_set_ctx_t ctx0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip40 = vlib_buffer_get_current (b0); - - ctx0.b = b0; - ctx0.vm = vm; - - next0 = NAT64_OUT2IN_NEXT_LOOKUP; - - proto0 = ip_proto_to_snat_proto (ip40->protocol); - - if (proto0 == SNAT_PROTOCOL_ICMP) - { - if (icmp_to_icmp6 - (b0, nat64_out2in_icmp_set_cb, &ctx0, - nat64_out2in_inner_icmp_set_cb, &ctx0)) - { - next0 = NAT64_OUT2IN_NEXT_DROP; - b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace0; - } - } - else if (proto0 == SNAT_PROTOCOL_TCP || proto0 == SNAT_PROTOCOL_UDP) - { - if (ip4_to_ip6_tcp_udp (b0, nat64_out2in_tcp_udp_set_cb, &ctx0)) - { - next0 = NAT64_OUT2IN_NEXT_DROP; - b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace0; - } - } - else - { - if (ip4_to_ip6 (b0, nat64_out2in_unk_proto_set_cb, &ctx0)) - { - next0 = NAT64_OUT2IN_NEXT_DROP; - b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace0; - } - } - - trace0: - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - nat64_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->next_index = next0; - } - - pkts_processed += next0 != NAT64_OUT2IN_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - vlib_node_increment_counter (vm, nat64_out2in_node.index, - NAT64_OUT2IN_ERROR_OUT2IN_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (nat64_out2in_node) = { - .function = nat64_out2in_node_fn, - .name = "nat64-out2in", - .vector_size = sizeof (u32), - .format_trace = format_nat64_out2in_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (nat64_out2in_error_strings), - .error_strings = nat64_out2in_error_strings,.n_next_nodes = 2, - /* edit / add dispositions here */ - .next_nodes = { - [NAT64_OUT2IN_NEXT_DROP] = "error-drop", - [NAT64_OUT2IN_NEXT_LOOKUP] = "ip6-lookup", - }, -}; -/* *INDENT-ON* */ - -VLIB_NODE_FUNCTION_MULTIARCH (nat64_out2in_node, nat64_out2in_node_fn); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c deleted file mode 100644 index 329d67dc3bf..00000000000 --- a/src/plugins/snat/out2in.c +++ /dev/null @@ -1,2294 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <vlib/vlib.h> -#include <vnet/vnet.h> -#include <vnet/pg/pg.h> -#include <vnet/handoff.h> - -#include <vnet/ip/ip.h> -#include <vnet/udp/udp.h> -#include <vnet/ethernet/ethernet.h> -#include <vnet/fib/ip4_fib.h> -#include <snat/snat.h> -#include <snat/snat_ipfix_logging.h> -#include <snat/snat_det.h> - -#include <vppinfra/hash.h> -#include <vppinfra/error.h> -#include <vppinfra/elog.h> - -typedef struct { - u32 sw_if_index; - u32 next_index; - u32 session_index; -} snat_out2in_trace_t; - -typedef struct { - u32 next_worker_index; - u8 do_handoff; -} snat_out2in_worker_handoff_trace_t; - -/* packet trace format function */ -static u8 * format_snat_out2in_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *); - - s = format (s, "SNAT_OUT2IN: sw_if_index %d, next index %d, session index %d", - t->sw_if_index, t->next_index, t->session_index); - return s; -} - -static u8 * format_snat_out2in_fast_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *); - - s = format (s, "SNAT_OUT2IN_FAST: sw_if_index %d, next index %d", - t->sw_if_index, t->next_index); - return s; -} - -static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - snat_out2in_worker_handoff_trace_t * t = - va_arg (*args, snat_out2in_worker_handoff_trace_t *); - char * m; - - m = t->do_handoff ? "next worker" : "same worker"; - s = format (s, "SNAT_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index); - - return s; -} - -vlib_node_registration_t snat_out2in_node; -vlib_node_registration_t snat_out2in_fast_node; -vlib_node_registration_t snat_out2in_worker_handoff_node; -vlib_node_registration_t snat_det_out2in_node; - -#define foreach_snat_out2in_error \ -_(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ -_(OUT2IN_PACKETS, "Good out2in packets processed") \ -_(BAD_ICMP_TYPE, "unsupported ICMP type") \ -_(NO_TRANSLATION, "No translation") - -typedef enum { -#define _(sym,str) SNAT_OUT2IN_ERROR_##sym, - foreach_snat_out2in_error -#undef _ - SNAT_OUT2IN_N_ERROR, -} snat_out2in_error_t; - -static char * snat_out2in_error_strings[] = { -#define _(sym,string) string, - foreach_snat_out2in_error -#undef _ -}; - -typedef enum { - SNAT_OUT2IN_NEXT_DROP, - SNAT_OUT2IN_NEXT_LOOKUP, - SNAT_OUT2IN_NEXT_ICMP_ERROR, - SNAT_OUT2IN_N_NEXT, -} snat_out2in_next_t; - -/** - * @brief Create session for static mapping. - * - * Create NAT session initiated by host from external network with static - * mapping. - * - * @param sm SNAT main. - * @param b0 Vlib buffer. - * @param in2out In2out SNAT session key. - * @param out2in Out2in SNAT session key. - * @param node Vlib node. - * - * @returns SNAT session if successfully created otherwise 0. - */ -static inline snat_session_t * -create_session_for_static_mapping (snat_main_t *sm, - vlib_buffer_t *b0, - snat_session_key_t in2out, - snat_session_key_t out2in, - vlib_node_runtime_t * node, - u32 thread_index) -{ - snat_user_t *u; - snat_user_key_t user_key; - snat_session_t *s; - clib_bihash_kv_8_8_t kv0, value0; - dlist_elt_t * per_user_translation_list_elt; - dlist_elt_t * per_user_list_head_elt; - ip4_header_t *ip0; - - ip0 = vlib_buffer_get_current (b0); - - user_key.addr = in2out.addr; - user_key.fib_index = in2out.fib_index; - kv0.key = user_key.as_u64; - - /* Ever heard of the "user" = inside ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) - { - /* no, make a new one */ - pool_get (sm->per_thread_data[thread_index].users, u); - memset (u, 0, sizeof (*u)); - u->addr = in2out.addr; - u->fib_index = in2out.fib_index; - - pool_get (sm->per_thread_data[thread_index].list_pool, - per_user_list_head_elt); - - u->sessions_per_user_list_head_index = per_user_list_head_elt - - sm->per_thread_data[thread_index].list_pool; - - clib_dlist_init (sm->per_thread_data[thread_index].list_pool, - u->sessions_per_user_list_head_index); - - kv0.value = u - sm->per_thread_data[thread_index].users; - - /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); - - /* add non-traslated packets worker lookup */ - kv0.value = thread_index; - clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); - } - else - { - u = pool_elt_at_index (sm->per_thread_data[thread_index].users, - value0.value); - } - - pool_get (sm->per_thread_data[thread_index].sessions, s); - memset (s, 0, sizeof (*s)); - - s->outside_address_index = ~0; - s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - s->ext_host_addr.as_u32 = ip0->dst_address.as_u32; - u->nstaticsessions++; - - /* Create list elts */ - pool_get (sm->per_thread_data[thread_index].list_pool, - per_user_translation_list_elt); - clib_dlist_init (sm->per_thread_data[thread_index].list_pool, - per_user_translation_list_elt - - sm->per_thread_data[thread_index].list_pool); - - per_user_translation_list_elt->value = - s - sm->per_thread_data[thread_index].sessions; - s->per_user_index = - per_user_translation_list_elt - sm->per_thread_data[thread_index].list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s->per_user_list_head_index, - per_user_translation_list_elt - - sm->per_thread_data[thread_index].list_pool); - - s->in2out = in2out; - s->out2in = out2in; - s->in2out.protocol = out2in.protocol; - - /* Add to translation hashes */ - kv0.key = s->in2out.as_u64; - kv0.value = s - sm->per_thread_data[thread_index].sessions; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) - clib_warning ("in2out key add failed"); - - kv0.key = s->out2in.as_u64; - kv0.value = s - sm->per_thread_data[thread_index].sessions; - - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) - clib_warning ("out2in key add failed"); - - /* log NAT event */ - snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32, - s->out2in.addr.as_u32, - s->in2out.protocol, - s->in2out.port, - s->out2in.port, - s->in2out.fib_index); - return s; -} - -static_always_inline -snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, - snat_session_key_t *p_key0) -{ - icmp46_header_t *icmp0; - snat_session_key_t key0; - icmp_echo_header_t *echo0, *inner_echo0 = 0; - ip4_header_t *inner_ip0; - void *l4_header = 0; - icmp46_header_t *inner_icmp0; - - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - echo0 = (icmp_echo_header_t *)(icmp0+1); - - if (!icmp_is_error_message (icmp0)) - { - key0.protocol = SNAT_PROTOCOL_ICMP; - key0.addr = ip0->dst_address; - key0.port = echo0->identifier; - } - else - { - inner_ip0 = (ip4_header_t *)(echo0+1); - l4_header = ip4_next_header (inner_ip0); - key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol); - key0.addr = inner_ip0->src_address; - switch (key0.protocol) - { - case SNAT_PROTOCOL_ICMP: - inner_icmp0 = (icmp46_header_t*)l4_header; - inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); - key0.port = inner_echo0->identifier; - break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - key0.port = ((tcp_udp_header_t*)l4_header)->src_port; - break; - default: - return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL; - } - } - *p_key0 = key0; - return -1; /* success */ -} - -/** - * Get address and port values to be used for packet SNAT translation - * and create session if needed - * - * @param[in,out] sm SNAT main - * @param[in,out] node SNAT node runtime - * @param[in] thread_index thread index - * @param[in,out] b0 buffer containing packet to be translated - * @param[out] p_proto protocol used for matching - * @param[out] p_value address and port after NAT translation - * @param[out] p_dont_translate if packet should not be translated - * @param d optional parameter - * @param e optional parameter - */ -u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e) -{ - ip4_header_t *ip0; - icmp46_header_t *icmp0; - u32 sw_if_index0; - u32 rx_fib_index0; - snat_session_key_t key0; - snat_session_key_t sm0; - snat_session_t *s0 = 0; - u8 dont_translate = 0; - clib_bihash_kv_8_8_t kv0, value0; - u8 is_addr_only; - u32 next0 = ~0; - int err; - - ip0 = vlib_buffer_get_current (b0); - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); - - key0.protocol = 0; - - err = icmp_get_key (ip0, &key0); - if (err != -1) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only)) - { - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, - ip0->dst_address.as_u32))) - { - dont_translate = 1; - goto out; - } - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply && - (icmp0->type != ICMP4_echo_request || !is_addr_only))) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - /* Create session initiated by host from external network */ - s0 = create_session_for_static_mapping(sm, b0, sm0, key0, - node, thread_index); - - if (!s0) - { - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - } - else - { - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply && - icmp0->type != ICMP4_echo_request && - !icmp_is_error_message (icmp0))) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); - } - -out: - *p_proto = key0.protocol; - if (s0) - *p_value = s0->in2out; - *p_dont_translate = dont_translate; - if (d) - *(snat_session_t**)d = s0; - return next0; -} - -/** - * Get address and port values to be used for packet SNAT translation - * - * @param[in] sm SNAT main - * @param[in,out] node SNAT node runtime - * @param[in] thread_index thread index - * @param[in,out] b0 buffer containing packet to be translated - * @param[out] p_proto protocol used for matching - * @param[out] p_value address and port after NAT translation - * @param[out] p_dont_translate if packet should not be translated - * @param d optional parameter - * @param e optional parameter - */ -u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e) -{ - ip4_header_t *ip0; - icmp46_header_t *icmp0; - u32 sw_if_index0; - u32 rx_fib_index0; - snat_session_key_t key0; - snat_session_key_t sm0; - u8 dont_translate = 0; - u8 is_addr_only; - u32 next0 = ~0; - int err; - - ip0 = vlib_buffer_get_current (b0); - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); - - err = icmp_get_key (ip0, &key0); - if (err != -1) - { - b0->error = node->errors[err]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out2; - } - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only)) - { - /* Don't NAT packet aimed at the intfc address */ - if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32)) - { - dont_translate = 1; - goto out; - } - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply && - (icmp0->type != ICMP4_echo_request || !is_addr_only) && - !icmp_is_error_message (icmp0))) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - -out: - *p_value = sm0; -out2: - *p_proto = key0.protocol; - *p_dont_translate = dont_translate; - return next0; -} - -static inline u32 icmp_out2in (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - u32 rx_fib_index0, - vlib_node_runtime_t * node, - u32 next0, - u32 thread_index, - void *d, - void *e) -{ - snat_session_key_t sm0; - u8 protocol; - icmp_echo_header_t *echo0, *inner_echo0 = 0; - ip4_header_t *inner_ip0 = 0; - void *l4_header = 0; - icmp46_header_t *inner_icmp0; - u8 dont_translate; - u32 new_addr0, old_addr0; - u16 old_id0, new_id0; - ip_csum_t sum0; - u16 checksum0; - u32 next0_tmp; - - echo0 = (icmp_echo_header_t *)(icmp0+1); - - next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, - &protocol, &sm0, &dont_translate, d, e); - if (next0_tmp != ~0) - next0 = next0_tmp; - if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate) - goto out; - - sum0 = ip_incremental_checksum (0, icmp0, - ntohs(ip0->length) - ip4_header_bytes (ip0)); - checksum0 = ~ip_csum_fold (sum0); - if (checksum0 != 0 && checksum0 != 0xffff) - { - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - old_addr0 = ip0->dst_address.as_u32; - new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (!icmp_is_error_message (icmp0)) - { - new_id0 = sm0.port; - if (PREDICT_FALSE(new_id0 != echo0->identifier)) - { - old_id0 = echo0->identifier; - new_id0 = sm0.port; - echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier /* changed member */); - icmp0->checksum = ip_csum_fold (sum0); - } - } - else - { - inner_ip0 = (ip4_header_t *)(echo0+1); - l4_header = ip4_next_header (inner_ip0); - - if (!ip4_header_checksum_is_valid (inner_ip0)) - { - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - old_addr0 = inner_ip0->src_address.as_u32; - inner_ip0->src_address = sm0.addr; - new_addr0 = inner_ip0->src_address.as_u32; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, - src_address /* changed member */); - icmp0->checksum = ip_csum_fold (sum0); - - switch (protocol) - { - case SNAT_PROTOCOL_ICMP: - inner_icmp0 = (icmp46_header_t*)l4_header; - inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); - - old_id0 = inner_echo0->identifier; - new_id0 = sm0.port; - inner_echo0->identifier = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t, - identifier); - icmp0->checksum = ip_csum_fold (sum0); - break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - old_id0 = ((tcp_udp_header_t*)l4_header)->src_port; - new_id0 = sm0.port; - ((tcp_udp_header_t*)l4_header)->src_port = new_id0; - - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t, - src_port); - icmp0->checksum = ip_csum_fold (sum0); - break; - default: - ASSERT(0); - } - } - -out: - return next0; -} - - -static inline u32 icmp_out2in_slow_path (snat_main_t *sm, - vlib_buffer_t * b0, - ip4_header_t * ip0, - icmp46_header_t * icmp0, - u32 sw_if_index0, - u32 rx_fib_index0, - vlib_node_runtime_t * node, - u32 next0, f64 now, - u32 thread_index, - snat_session_t ** p_s0) -{ - next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, thread_index, p_s0, 0); - snat_session_t * s0 = *p_s0; - if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0)) - { - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - } - return next0; -} - -static void -snat_out2in_unknown_proto (snat_main_t *sm, - vlib_buffer_t * b, - ip4_header_t * ip, - u32 rx_fib_index, - u32 thread_index, - f64 now, - vlib_main_t * vm) -{ - clib_bihash_kv_8_8_t kv, value; - clib_bihash_kv_16_8_t s_kv, s_value; - snat_static_mapping_t *m; - snat_session_key_t m_key; - u32 old_addr, new_addr; - ip_csum_t sum; - snat_unk_proto_ses_key_t key; - snat_session_t * s; - snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - snat_user_key_t u_key; - snat_user_t *u; - dlist_elt_t *head, *elt; - - old_addr = ip->dst_address.as_u32; - - key.l_addr = ip->dst_address; - key.r_addr = ip->src_address; - key.fib_index = rx_fib_index; - key.proto = ip->protocol; - key.rsvd[0] = key.rsvd[1] = key.rsvd[2] = 0; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - - if (!clib_bihash_search_16_8 (&sm->out2in_unk_proto, &s_kv, &s_value)) - { - s = pool_elt_at_index (tsm->sessions, s_value.value); - new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32; - } - else - { - m_key.addr = ip->dst_address; - m_key.port = 0; - m_key.protocol = 0; - m_key.fib_index = rx_fib_index; - kv.key = m_key.as_u64; - if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) - return; - - m = pool_elt_at_index (sm->static_mappings, value.value); - - new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32; - - u_key.addr = ip->src_address; - u_key.fib_index = m->fib_index; - kv.key = u_key.as_u64; - - /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) - { - /* no, make a new one */ - pool_get (tsm->users, u); - memset (u, 0, sizeof (*u)); - u->addr = ip->src_address; - u->fib_index = rx_fib_index; - - pool_get (tsm->list_pool, head); - u->sessions_per_user_list_head_index = head - tsm->list_pool; - - clib_dlist_init (tsm->list_pool, - u->sessions_per_user_list_head_index); - - kv.value = u - tsm->users; - - /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 1); - } - else - { - u = pool_elt_at_index (tsm->users, value.value); - } - - /* Create a new session */ - pool_get (tsm->sessions, s); - memset (s, 0, sizeof (*s)); - - s->ext_host_addr.as_u32 = ip->src_address.as_u32; - s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; - s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - s->outside_address_index = ~0; - s->out2in.addr.as_u32 = old_addr; - s->out2in.fib_index = rx_fib_index; - s->in2out.addr.as_u32 = new_addr; - s->in2out.fib_index = m->fib_index; - s->in2out.port = s->out2in.port = ip->protocol; - u->nstaticsessions++; - - /* Create list elts */ - pool_get (tsm->list_pool, elt); - clib_dlist_init (tsm->list_pool, elt - tsm->list_pool); - elt->value = s - tsm->sessions; - s->per_user_index = elt - tsm->list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); - - /* Add to lookup tables */ - s_kv.value = s - tsm->sessions; - if (clib_bihash_add_del_16_8 (&sm->out2in_unk_proto, &s_kv, 1)) - clib_warning ("out2in key add failed"); - - key.l_addr = ip->dst_address; - key.fib_index = m->fib_index; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_unk_proto, &s_kv, 1)) - clib_warning ("in2out key add failed"); - } - - /* Update IP checksum */ - sum = ip->checksum; - sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); - ip->checksum = ip_csum_fold (sum); - - vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index; - - /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); - /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); -} - -static uword -snat_out2in_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_out2in_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - f64 now = vlib_time_now (vm); - u32 thread_index = vlib_get_thread_index (); - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 sw_if_index0, sw_if_index1; - ip4_header_t * ip0, *ip1; - ip_csum_t sum0, sum1; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - u32 new_addr1, old_addr1; - u16 new_port1, old_port1; - udp_header_t * udp0, * udp1; - tcp_header_t * tcp0, * tcp1; - icmp46_header_t * icmp0, * icmp1; - snat_session_key_t key0, key1, sm0, sm1; - u32 rx_fib_index0, rx_fib_index1; - u32 proto0, proto1; - snat_session_t * s0 = 0, * s1 = 0; - clib_bihash_kv_8_8_t kv0, kv1, value0, value1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - vnet_buffer (b0)->snat.flags = 0; - vnet_buffer (b1)->snat.flags = 0; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR; - goto trace0; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - { - snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, - thread_index, now, vm); - goto trace0; - } - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_out2in_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, thread_index, &s0); - goto trace0; - } - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key0, &sm0, 1, 0)) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - /* - * Send DHCP packets to the ipv4 stack, or we won't - * be able to use dhcp client on the outside interface - */ - if (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace0; - } - - /* Create session initiated by host from external network */ - s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, - thread_index); - if (!s0) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace0; - } - } - else - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); - - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address = s0->in2out.addr; - new_addr0 = ip0->dst_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->dst_port; - tcp0->dst_port = s0->in2out.port; - new_port0 = tcp0->dst_port; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = s0->in2out.port; - udp0->checksum = 0; - } - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - trace0: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[thread_index].sessions; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - - ip1 = vlib_buffer_get_current (b1); - udp1 = ip4_next_header (ip1); - tcp1 = (tcp_header_t *) udp1; - icmp1 = (icmp46_header_t *) udp1; - - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index1); - - if (PREDICT_FALSE(ip1->ttl == 1)) - { - vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR; - goto trace1; - } - - proto1 = ip_proto_to_snat_proto (ip1->protocol); - - if (PREDICT_FALSE (proto1 == ~0)) - { - snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1, - thread_index, now, vm); - goto trace1; - } - - if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP)) - { - next1 = icmp_out2in_slow_path - (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, - next1, now, thread_index, &s1); - goto trace1; - } - - key1.addr = ip1->dst_address; - key1.port = udp1->dst_port; - key1.protocol = proto1; - key1.fib_index = rx_fib_index1; - - kv1.key = key1.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv1, &value1)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key1, &sm1, 1, 0)) - { - b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - /* - * Send DHCP packets to the ipv4 stack, or we won't - * be able to use dhcp client on the outside interface - */ - if (proto1 != SNAT_PROTOCOL_UDP - || (udp1->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - next1 = SNAT_OUT2IN_NEXT_DROP; - goto trace1; - } - - /* Create session initiated by host from external network */ - s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node, - thread_index); - if (!s1) - { - b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next1 = SNAT_OUT2IN_NEXT_DROP; - goto trace1; - } - } - else - s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value1.value); - - old_addr1 = ip1->dst_address.as_u32; - ip1->dst_address = s1->in2out.addr; - new_addr1 = ip1->dst_address.as_u32; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index; - - sum1 = ip1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - dst_address /* changed member */); - ip1->checksum = ip_csum_fold (sum1); - - if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) - { - old_port1 = tcp1->dst_port; - tcp1->dst_port = s1->in2out.port; - new_port1 = tcp1->dst_port; - - sum1 = tcp1->checksum; - sum1 = ip_csum_update (sum1, old_addr1, new_addr1, - ip4_header_t, - dst_address /* changed member */); - - sum1 = ip_csum_update (sum1, old_port1, new_port1, - ip4_header_t /* cheat */, - length /* changed member */); - tcp1->checksum = ip_csum_fold(sum1); - } - else - { - old_port1 = udp1->dst_port; - udp1->dst_port = s1->in2out.port; - udp1->checksum = 0; - } - - /* Accounting */ - s1->last_heard = now; - s1->total_pkts++; - s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s1)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s1->per_user_list_head_index, - s1->per_user_index); - } - trace1: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b1->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - t->next_index = next1; - t->session_index = ~0; - if (s1) - t->session_index = s1 - sm->per_thread_data[thread_index].sessions; - } - - pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP; - - /* verify speculative enqueues, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0, sm0; - u32 rx_fib_index0; - u32 proto0; - snat_session_t * s0 = 0; - clib_bihash_kv_8_8_t kv0, value0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - vnet_buffer (b0)->snat.flags = 0; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, - sw_if_index0); - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - { - snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, - thread_index, now, vm); - goto trace00; - } - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR; - goto trace00; - } - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_out2in_slow_path - (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, thread_index, &s0); - goto trace00; - } - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.protocol = proto0; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) - { - /* Try to match static mapping by external address and port, - destination address and port in packet */ - if (snat_static_mapping_match(sm, key0, &sm0, 1, 0)) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - /* - * Send DHCP packets to the ipv4 stack, or we won't - * be able to use dhcp client on the outside interface - */ - if (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace00; - } - - /* Create session initiated by host from external network */ - s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, - thread_index); - if (!s0) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace00; - } - } - else - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); - - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address = s0->in2out.addr; - new_addr0 = ip0->dst_address.as_u32; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->dst_port; - tcp0->dst_port = s0->in2out.port; - new_port0 = tcp0->dst_port; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = s0->in2out.port; - udp0->checksum = 0; - } - - /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); - } - trace00: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (s0) - t->session_index = s0 - sm->per_thread_data[thread_index].sessions; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, snat_out2in_node.index, - SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_out2in_node) = { - .function = snat_out2in_node_fn, - .name = "snat-out2in", - .vector_size = sizeof (u32), - .format_trace = format_snat_out2in_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_out2in_error_strings), - .error_strings = snat_out2in_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_OUT2IN_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_OUT2IN_NEXT_DROP] = "error-drop", - [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; -VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn); - -/**************************/ -/*** deterministic mode ***/ -/**************************/ -static uword -snat_det_out2in_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_out2in_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - u32 thread_index = vlib_get_thread_index (); - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 sw_if_index0, sw_if_index1; - ip4_header_t * ip0, * ip1; - ip_csum_t sum0, sum1; - ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1; - u16 new_port0, old_port0, old_port1, new_port1; - udp_header_t * udp0, * udp1; - tcp_header_t * tcp0, * tcp1; - u32 proto0, proto1; - snat_det_out_key_t key0, key1; - snat_det_map_t * dm0, * dm1; - snat_det_session_t * ses0 = 0, * ses1 = 0; - u32 rx_fib_index0, rx_fib_index1; - icmp46_header_t * icmp0, * icmp1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR; - goto trace0; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) - { - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - icmp0 = (icmp46_header_t *) udp0; - - next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, thread_index, - &ses0, &dm0); - goto trace0; - } - - key0.ext_host_addr = ip0->src_address; - key0.ext_host_port = tcp0->src; - key0.out_port = tcp0->dst; - - dm0 = snat_det_map_by_out(sm, &ip0->dst_address); - if (PREDICT_FALSE(!dm0)) - { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); - next0 = SNAT_OUT2IN_NEXT_DROP; - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace0; - } - - snat_det_reverse(dm0, &ip0->dst_address, - clib_net_to_host_u16(tcp0->dst), &new_addr0); - - ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); - if (PREDICT_FALSE(!ses0)) - { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip0->src_address, - clib_net_to_host_u16 (tcp0->src), - format_ip4_address, &ip0->dst_address, - clib_net_to_host_u16 (tcp0->dst), - format_ip4_address, &new_addr0); - next0 = SNAT_OUT2IN_NEXT_DROP; - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace0; - } - new_port0 = ses0->in_port; - - old_addr0 = ip0->dst_address; - ip0->dst_address = new_addr0; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED) - ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT; - else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK) - snat_det_ses_close(dm0, ses0); - - old_port0 = tcp0->dst; - tcp0->dst = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = new_port0; - udp0->checksum = 0; - } - - trace0: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (ses0) - t->session_index = ses0 - dm0->sessions; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - b1 = vlib_get_buffer (vm, bi1); - - ip1 = vlib_buffer_get_current (b1); - udp1 = ip4_next_header (ip1); - tcp1 = (tcp_header_t *) udp1; - - sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX]; - - if (PREDICT_FALSE(ip1->ttl == 1)) - { - vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR; - goto trace1; - } - - proto1 = ip_proto_to_snat_proto (ip1->protocol); - - if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP)) - { - rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1); - icmp1 = (icmp46_header_t *) udp1; - - next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1, - rx_fib_index1, node, next1, thread_index, - &ses1, &dm1); - goto trace1; - } - - key1.ext_host_addr = ip1->src_address; - key1.ext_host_port = tcp1->src; - key1.out_port = tcp1->dst; - - dm1 = snat_det_map_by_out(sm, &ip1->dst_address); - if (PREDICT_FALSE(!dm1)) - { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip1->dst_address); - next1 = SNAT_OUT2IN_NEXT_DROP; - b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace1; - } - - snat_det_reverse(dm1, &ip1->dst_address, - clib_net_to_host_u16(tcp1->dst), &new_addr1); - - ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64); - if (PREDICT_FALSE(!ses1)) - { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip1->src_address, - clib_net_to_host_u16 (tcp1->src), - format_ip4_address, &ip1->dst_address, - clib_net_to_host_u16 (tcp1->dst), - format_ip4_address, &new_addr1); - next1 = SNAT_OUT2IN_NEXT_DROP; - b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace1; - } - new_port1 = ses1->in_port; - - old_addr1 = ip1->dst_address; - ip1->dst_address = new_addr1; - vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index; - - sum1 = ip1->checksum; - sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32, - ip4_header_t, - dst_address /* changed member */); - ip1->checksum = ip_csum_fold (sum1); - - if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP)) - { - if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED) - ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT; - else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK) - snat_det_ses_close(dm1, ses1); - - old_port1 = tcp1->dst; - tcp1->dst = new_port1; - - sum1 = tcp1->checksum; - sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32, - ip4_header_t, - dst_address /* changed member */); - - sum1 = ip_csum_update (sum1, old_port1, new_port1, - ip4_header_t /* cheat */, - length /* changed member */); - tcp1->checksum = ip_csum_fold(sum1); - } - else - { - old_port1 = udp1->dst_port; - udp1->dst_port = new_port1; - udp1->checksum = 0; - } - - trace1: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b1->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - t->next_index = next1; - t->session_index = ~0; - if (ses1) - t->session_index = ses1 - dm1->sessions; - } - - pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP; - - /* verify speculative enqueues, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - ip4_address_t new_addr0, old_addr0; - u16 new_port0, old_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - u32 proto0; - snat_det_out_key_t key0; - snat_det_map_t * dm0; - snat_det_session_t * ses0 = 0; - u32 rx_fib_index0; - icmp46_header_t * icmp0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR; - goto trace00; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) - { - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - icmp0 = (icmp46_header_t *) udp0; - - next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, thread_index, - &ses0, &dm0); - goto trace00; - } - - key0.ext_host_addr = ip0->src_address; - key0.ext_host_port = tcp0->src; - key0.out_port = tcp0->dst; - - dm0 = snat_det_map_by_out(sm, &ip0->dst_address); - if (PREDICT_FALSE(!dm0)) - { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); - next0 = SNAT_OUT2IN_NEXT_DROP; - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace00; - } - - snat_det_reverse(dm0, &ip0->dst_address, - clib_net_to_host_u16(tcp0->dst), &new_addr0); - - ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); - if (PREDICT_FALSE(!ses0)) - { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip0->src_address, - clib_net_to_host_u16 (tcp0->src), - format_ip4_address, &ip0->dst_address, - clib_net_to_host_u16 (tcp0->dst), - format_ip4_address, &new_addr0); - next0 = SNAT_OUT2IN_NEXT_DROP; - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace00; - } - new_port0 = ses0->in_port; - - old_addr0 = ip0->dst_address; - ip0->dst_address = new_addr0; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED) - ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT; - else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK) - snat_det_ses_close(dm0, ses0); - - old_port0 = tcp0->dst; - tcp0->dst = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = new_port0; - udp0->checksum = 0; - } - - trace00: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->session_index = ~0; - if (ses0) - t->session_index = ses0 - dm0->sessions; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, snat_det_out2in_node.index, - SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_det_out2in_node) = { - .function = snat_det_out2in_node_fn, - .name = "snat-det-out2in", - .vector_size = sizeof (u32), - .format_trace = format_snat_out2in_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_out2in_error_strings), - .error_strings = snat_out2in_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_OUT2IN_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_OUT2IN_NEXT_DROP] = "error-drop", - [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; -VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn); - -/** - * Get address and port values to be used for packet SNAT translation - * and create session if needed - * - * @param[in,out] sm SNAT main - * @param[in,out] node SNAT node runtime - * @param[in] thread_index thread index - * @param[in,out] b0 buffer containing packet to be translated - * @param[out] p_proto protocol used for matching - * @param[out] p_value address and port after NAT translation - * @param[out] p_dont_translate if packet should not be translated - * @param d optional parameter - * @param e optional parameter - */ -u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e) -{ - ip4_header_t *ip0; - icmp46_header_t *icmp0; - u32 sw_if_index0; - u8 protocol; - snat_det_out_key_t key0; - u8 dont_translate = 0; - u32 next0 = ~0; - icmp_echo_header_t *echo0, *inner_echo0 = 0; - ip4_header_t *inner_ip0; - void *l4_header = 0; - icmp46_header_t *inner_icmp0; - snat_det_map_t * dm0 = 0; - ip4_address_t new_addr0 = {{0}}; - snat_det_session_t * ses0 = 0; - ip4_address_t out_addr; - - ip0 = vlib_buffer_get_current (b0); - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - echo0 = (icmp_echo_header_t *)(icmp0+1); - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - if (!icmp_is_error_message (icmp0)) - { - protocol = SNAT_PROTOCOL_ICMP; - key0.ext_host_addr = ip0->src_address; - key0.ext_host_port = 0; - key0.out_port = echo0->identifier; - out_addr = ip0->dst_address; - } - else - { - inner_ip0 = (ip4_header_t *)(echo0+1); - l4_header = ip4_next_header (inner_ip0); - protocol = ip_proto_to_snat_proto (inner_ip0->protocol); - key0.ext_host_addr = inner_ip0->dst_address; - out_addr = inner_ip0->src_address; - switch (protocol) - { - case SNAT_PROTOCOL_ICMP: - inner_icmp0 = (icmp46_header_t*)l4_header; - inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); - key0.ext_host_port = 0; - key0.out_port = inner_echo0->identifier; - break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port; - key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port; - break; - default: - b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - } - - dm0 = snat_det_map_by_out(sm, &out_addr); - if (PREDICT_FALSE(!dm0)) - { - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, - ip0->dst_address.as_u32))) - { - dont_translate = 1; - goto out; - } - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); - goto out; - } - - snat_det_reverse(dm0, &ip0->dst_address, - clib_net_to_host_u16(key0.out_port), &new_addr0); - - ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); - if (PREDICT_FALSE(!ses0)) - { - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, - ip0->dst_address.as_u32))) - { - dont_translate = 1; - goto out; - } - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &key0.ext_host_addr, - clib_net_to_host_u16 (key0.ext_host_port), - format_ip4_address, &out_addr, - clib_net_to_host_u16 (key0.out_port), - format_ip4_address, &new_addr0); - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply && - !icmp_is_error_message (icmp0))) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; - } - - goto out; - -out: - *p_proto = protocol; - if (ses0) - { - p_value->addr = new_addr0; - p_value->fib_index = sm->inside_fib_index; - p_value->port = ses0->in_port; - } - *p_dont_translate = dont_translate; - if (d) - *(snat_det_session_t**)d = ses0; - if (e) - *(snat_det_map_t**)e = dm0; - return next0; -} - -/**********************/ -/*** worker handoff ***/ -/**********************/ -static uword -snat_out2in_worker_handoff_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - snat_main_t *sm = &snat_main; - vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 n_left_from, *from, *to_next = 0; - static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; - static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index - = 0; - vlib_frame_queue_elt_t *hf = 0; - vlib_frame_t *f = 0; - int i; - u32 n_left_to_next_worker = 0, *to_next_worker = 0; - u32 next_worker_index = 0; - u32 current_worker_index = ~0; - u32 thread_index = vlib_get_thread_index (); - - ASSERT (vec_len (sm->workers)); - - if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0)) - { - vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); - - vec_validate_init_empty (congested_handoff_queue_by_worker_index, - sm->first_worker_index + sm->num_workers - 1, - (vlib_frame_queue_t *) (~0)); - } - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 sw_if_index0; - u32 rx_fib_index0; - ip4_header_t * ip0; - u8 do_handoff; - - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - ip0 = vlib_buffer_get_current (b0); - - next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0); - - if (PREDICT_FALSE (next_worker_index != thread_index)) - { - do_handoff = 1; - - if (next_worker_index != current_worker_index) - { - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index, - next_worker_index, - handoff_queue_elt_by_worker_index); - - n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors; - to_next_worker = &hf->buffer_index[hf->n_vectors]; - current_worker_index = next_worker_index; - } - - /* enqueue to correct worker thread */ - to_next_worker[0] = bi0; - to_next_worker++; - n_left_to_next_worker--; - - if (n_left_to_next_worker == 0) - { - hf->n_vectors = VLIB_FRAME_SIZE; - vlib_put_frame_queue_elt (hf); - current_worker_index = ~0; - handoff_queue_elt_by_worker_index[next_worker_index] = 0; - hf = 0; - } - } - else - { - do_handoff = 0; - /* if this is 1st frame */ - if (!f) - { - f = vlib_get_frame_to_node (vm, sm->out2in_node_index); - to_next = vlib_frame_vector_args (f); - } - - to_next[0] = bi0; - to_next += 1; - f->n_vectors++; - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_worker_handoff_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->next_worker_index = next_worker_index; - t->do_handoff = do_handoff; - } - } - - if (f) - vlib_put_frame_to_node (vm, sm->out2in_node_index, f); - - if (hf) - hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; - - /* Ship frames to the worker nodes */ - for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++) - { - if (handoff_queue_elt_by_worker_index[i]) - { - hf = handoff_queue_elt_by_worker_index[i]; - /* - * It works better to let the handoff node - * rate-adapt, always ship the handoff queue element. - */ - if (1 || hf->n_vectors == hf->last_n_vectors) - { - vlib_put_frame_queue_elt (hf); - handoff_queue_elt_by_worker_index[i] = 0; - } - else - hf->last_n_vectors = hf->n_vectors; - } - congested_handoff_queue_by_worker_index[i] = - (vlib_frame_queue_t *) (~0); - } - hf = 0; - current_worker_index = ~0; - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = { - .function = snat_out2in_worker_handoff_fn, - .name = "snat-out2in-worker-handoff", - .vector_size = sizeof (u32), - .format_trace = format_snat_out2in_worker_handoff_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_worker_handoff_node, snat_out2in_worker_handoff_fn); - -static uword -snat_out2in_fast_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - snat_out2in_next_t next_index; - u32 pkts_processed = 0; - snat_main_t * sm = &snat_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - u32 next0 = SNAT_OUT2IN_NEXT_DROP; - u32 sw_if_index0; - ip4_header_t * ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - udp_header_t * udp0; - tcp_header_t * tcp0; - icmp46_header_t * icmp0; - snat_session_key_t key0, sm0; - u32 proto0; - u32 rx_fib_index0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - - vnet_feature_next (sw_if_index0, &next0, b0); - - if (PREDICT_FALSE(ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR; - goto trace00; - } - - proto0 = ip_proto_to_snat_proto (ip0->protocol); - - if (PREDICT_FALSE (proto0 == ~0)) - goto trace00; - - if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) - { - next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, ~0, 0, 0); - goto trace00; - } - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.fib_index = rx_fib_index0; - - if (snat_static_mapping_match(sm, key0, &sm0, 1, 0)) - { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace00; - } - - new_addr0 = sm0.addr.as_u32; - new_port0 = sm0.port; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE(new_port0 != udp0->dst_port)) - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - old_port0 = tcp0->dst_port; - tcp0->dst_port = new_port0; - - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */, - length /* changed member */); - tcp0->checksum = ip_csum_fold(sum0); - } - else - { - old_port0 = udp0->dst_port; - udp0->dst_port = new_port0; - udp0->checksum = 0; - } - } - else - { - if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */); - - tcp0->checksum = ip_csum_fold(sum0); - } - } - - trace00: - - if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - snat_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - - pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, snat_out2in_fast_node.index, - SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, - pkts_processed); - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (snat_out2in_fast_node) = { - .function = snat_out2in_fast_node_fn, - .name = "snat-out2in-fast", - .vector_size = sizeof (u32), - .format_trace = format_snat_out2in_fast_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(snat_out2in_error_strings), - .error_strings = snat_out2in_error_strings, - - .runtime_data_bytes = sizeof (snat_runtime_t), - - .n_next_nodes = SNAT_OUT2IN_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", - [SNAT_OUT2IN_NEXT_DROP] = "error-drop", - [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; -VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn); diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api deleted file mode 100644 index 3c493ddae5b..00000000000 --- a/src/plugins/snat/snat.api +++ /dev/null @@ -1,897 +0,0 @@ -/* - * Copyright (c) 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. - */ -/** - * @file snat.api - * @brief VPP control-plane API messages. - * - * This file defines VPP control-plane API messages which are generally - * called through a shared memory interface. - */ - -/** \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 - @param first_ip_address - first IP address - @param last_ip_address - last IP address - @param vrf_id - VRF id of tenant, ~0 means independent of VRF - @param is_add - 1 if add, 0 if delete -*/ -autoreply define snat_add_address_range { - u32 client_index; - u32 context; - u8 is_ip4; - u8 first_ip_address[16]; - u8 last_ip_address[16]; - u32 vrf_id; - u8 is_add; -}; - -/** \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 - @param vrf_id - VRF id of tenant, ~0 means independent of VRF -*/ -define snat_address_details { - u32 context; - u8 is_ip4; - u8 ip_address[16]; - u32 vrf_id; -}; - -/** \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 - @param is_add - 1 if add, 0 if delete - @param is_inside - 1 if inside, 0 if outside - @param sw_if_index - software index of the interface -*/ -autoreply define snat_interface_add_del_feature { - u32 client_index; - u32 context; - u8 is_add; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Dump interfaces with S-NAT feature - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_interface_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT interface details response - @param context - sender context, to match reply w/ request - @param is_inside - 1 if inside, 0 if outside - @param sw_if_index - software index of the interface -*/ -define snat_interface_details { - u32 context; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Enable/disbale S-NAT as an interface output feature (postrouting - in2out translation) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - 1 if add, 0 if delete - @param is_inside - 1 if inside, 0 if outside - @param sw_if_index - software index of the interface -*/ -autoreply define snat_interface_add_del_output_feature { - u32 client_index; - u32 context; - u8 is_add; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Dump interfaces with S-NAT output feature - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_interface_output_feature_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT interface with output feature details response - @param context - sender context, to match reply w/ request - @param is_inside - 1 if inside, 0 if outside - @param sw_if_index - software index of the interface -*/ -define snat_interface_output_feature_details { - u32 context; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Add/delete S-NAT static mapping - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - 1 if add, 0 if delete - @param is_ip4 - 1 if address type is IPv4 - @param addr_only - 1 if address only mapping - @param local_ip_address - local IP address - @param external_ip_address - external IP address - @param protocol - IP protocol - @param local_port - local port number - @param external_port - external port number - @param external_sw_if_index - external interface (if set - external_ip_address is ignored, ~0 means not - used) - @param vfr_id - VRF ID -*/ -autoreply define snat_add_static_mapping { - u32 client_index; - u32 context; - u8 is_add; - u8 is_ip4; - u8 addr_only; - u8 local_ip_address[16]; - u8 external_ip_address[16]; - u8 protocol; - u16 local_port; - u16 external_port; - u32 external_sw_if_index; - u32 vrf_id; -}; - -/** \brief Dump S-NAT static mappings - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_static_mapping_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT static mapping details response - @param context - sender context, to match reply w/ request - @param is_ip4 - 1 if address type is IPv4 - @param addr_only - 1 if address only mapping - @param local_ip_address - local IP address - @param external_ip_address - external IP address - @param protocol - IP protocol - @param local_port - local port number - @param external_port - external port number - @param external_sw_if_index - external interface - @param vfr_id - VRF ID -*/ -define snat_static_mapping_details { - u32 context; - u8 is_ip4; - u8 addr_only; - u8 local_ip_address[16]; - u8 external_ip_address[16]; - u8 protocol; - u16 local_port; - u16 external_port; - u32 external_sw_if_index; - u32 vrf_id; -}; - -/** \brief Control ping from client to api server request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_control_ping -{ - u32 client_index; - u32 context; -}; - -/** \brief Control ping from the client to the server response - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param vpe_pid - the pid of the vpe, returned by the server -*/ -define snat_control_ping_reply -{ - u32 context; - i32 retval; - u32 client_index; - u32 vpe_pid; -}; - -/** \brief Show S-NAT plugin startup config - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_show_config -{ - u32 client_index; - u32 context; -}; - -/** \brief Show S-NAT plugin startup config reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param static_mapping_only - if 1 dynamic translations disabled - @param static_mapping_connection_tracking - if 1 create session data - @param deterministic - if 1 deterministic mapping - @param translation_buckets - number of translation hash buckets - @param translation_memory_size - translation hash memory size - @param user_buckets - number of user hash buckets - @param user_memory_size - user hash memory size - @param max_translations_per_user - maximum number of translations per user - @param outside_vrf_id - outside VRF id - @param inside_vrf_id - default inside VRF id -*/ -define snat_show_config_reply -{ - u32 context; - i32 retval; - u8 static_mapping_only; - u8 static_mapping_connection_tracking; - u8 deterministic; - u32 translation_buckets; - u32 translation_memory_size; - u32 user_buckets; - u32 user_memory_size; - u32 max_translations_per_user; - u32 outside_vrf_id; - u32 inside_vrf_id; -}; - -/** \brief Set S-NAT workers - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param worker_mask - S-NAT workers mask -*/ -autoreply define snat_set_workers { - u32 client_index; - u32 context; - u64 worker_mask; -}; - -/** \brief Dump S-NAT workers - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_worker_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT workers details response - @param context - sender context, to match reply w/ request - @param worker_index - worker index - @param lcore_id - lcore ID - @param name - worker name -*/ -define snat_worker_details { - u32 context; - u32 worker_index; - u32 lcore_id; - u8 name[64]; -}; - -/** \brief Add/delete S-NAT pool address from specific interfce - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - 1 if add, 0 if delete - @param sw_if_index - software index of the interface -*/ -autoreply define snat_add_del_interface_addr { - u32 client_index; - u32 context; - u8 is_add; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Dump S-NAT pool addresses interfaces - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_interface_addr_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT pool addresses interfaces details response - @param context - sender context, to match reply w/ request - @param sw_if_index - software index of the interface -*/ -define snat_interface_addr_details { - u32 context; - u32 sw_if_index; -}; - -/** \brief Enable/disable S-NAT IPFIX logging - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param domain_id - observation domain ID - @param src_port - source port number - @param enable - 1 if enable, 0 if disable -*/ -autoreply define snat_ipfix_enable_disable { - u32 client_index; - u32 context; - u32 domain_id; - u16 src_port; - u8 enable; -}; - -/** \brief Dump S-NAT users - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_user_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT users response - @param context - sender context, to match reply w/ request - @vrf_id - VRF ID - @param is_ip4 - 1 if address type is IPv4 - @param ip_adress - IP address - @param nsessions - number of dynamic sessions - @param nstaticsessions - number of static sessions -*/ -define snat_user_details { - u32 context; - u32 vrf_id; - u8 is_ip4; - u8 ip_address[16]; - u32 nsessions; - u32 nstaticsessions; -}; - -/** \brief S-NAT user's sessions - @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 - @param user_ip - IP address of the user to dump - @param vrf_id - VRF_ID -*/ -define snat_user_session_dump { - u32 client_index; - u32 context; - u8 is_ip4; - u8 ip_address[16]; - u32 vrf_id; -}; - -/** \brief S-NAT user's sessions response - @param context - sender context, to match reply w/ request - @param is_ip4 - 1 if address type is IPv4 - @param outside_ip_address - outside IP address - @param outside_port - outside port - @param inside_ip_address - inside IP address - @param inside_port - inside port - @param protocol - protocol - @param is_static - 1 if session is static - @param last_heard - last heard timer - @param total_bytes - count of bytes sent through session - @param total_pkts - count of pakets sent through session -*/ -define snat_user_session_details { - u32 context; - u8 is_ip4; - u8 outside_ip_address[16]; - u16 outside_port; - u8 inside_ip_address[16]; - u16 inside_port; - u16 protocol; - u8 is_static; - u64 last_heard; - u64 total_bytes; - u32 total_pkts; -}; - -/** \brief Add/delete S-NAT deterministic mapping - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - 1 if add, 0 if delete - @param is_ip4 - 1 if address type is IPv4 - @param in_addr - inside IP address - @param in_plen - inside IP address prefix length - @param out_addr - outside IP address - @param out_addr - outside IP address prefix length -*/ -autoreply define snat_add_det_map { - u32 client_index; - u32 context; - u8 is_add; - u8 is_ip4; - u8 addr_only; - u8 in_addr[16]; - u8 in_plen; - u8 out_addr[16]; - u8 out_plen; -}; - -/** \brief Get outside address and port range from inside address - @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 - @param in_addr - inside IP address -*/ -define snat_det_forward { - u32 client_index; - u32 context; - u8 is_ip4; - u8 in_addr[16]; -}; - -/** \brief Get outside address and port range from inside address - @param context - sender context, to match reply w/ request - @param retval - return code - @param out_port_lo - outside port range start - @param out_port_hi - outside port range end - @param is_ip4 - 1 if address type is IPv4 - @param out_addr - outside IP address -*/ -define snat_det_forward_reply { - u32 context; - i32 retval; - u16 out_port_lo; - u16 out_port_hi; - u8 is_ip4; - u8 out_addr[16]; -}; - -/** \brief Get inside address from outside address and port - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param out_port - outside port - @param is_ip4 - 1 if address type is IPv4 - @param out_addr - outside IP address -*/ -define snat_det_reverse { - u32 client_index; - u32 context; - u16 out_port; - u8 is_ip4; - u8 out_addr[16]; -}; - -/** \brief Get inside address from outside address and port reply - @param context - sender context, to match reply w/ request - @param retval - return code - @param is_ip4 - 1 if address type is IPv4 - @param in_addr - inside IP address -*/ -define snat_det_reverse_reply { - u32 context; - i32 retval; - u8 is_ip4; - u8 in_addr[16]; -}; - -/** \brief Dump S-NAT deterministic mappings - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_det_map_dump { - u32 client_index; - u32 context; -}; - -/** \brief S-NAT users response - @param context - sender context, to match reply w/ request - @param is_ip4 - 1 if address type is IPv4 - @param in_addr - inside IP address - @param in_plen - inside IP address prefix length - @param out_addr - outside IP address - @param out_plen - outside IP address prefix length - @param sharing_ratio - outside to inside address sharing ratio - @param ports_per_host - number of ports available to a host - @param ses_num - number of sessions belonging to this mapping -*/ -define snat_det_map_details { - u32 context; - u8 is_ip4; - u8 in_addr[16]; - u8 in_plen; - u8 out_addr[16]; - u8 out_plen; - u32 sharing_ratio; - u16 ports_per_host; - u32 ses_num; -}; - -/** \brief Set values of timeouts for deterministic NAT (seconds, 0 = default) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param udp - UDP timeout (default 300sec) - @param tcp_established - TCP established timeout (default 7440sec) - @param tcp_transitory - TCP transitory timeout (default 240sec) - @param icmp - ICMP timeout (default 60sec) -*/ -autoreply define snat_det_set_timeouts { - u32 client_index; - u32 context; - u32 udp; - u32 tcp_established; - u32 tcp_transitory; - u32 icmp; -}; - -/** \brief Get values of timeouts for deterministic NAT (seconds) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define snat_det_get_timeouts { - u32 client_index; - u32 context; -}; - -/** \brief Get values of timeouts for deterministic NAT reply - @param context - sender context, to match reply w/ request - @param retval - return code - @param udp - UDP timeout (default 300sec) - @param tcp_established - TCP established timeout (default 7440sec) - @param tcp_transitory - TCP transitory timeout (default 240sec) - @param icmp - ICMP timeout (default 60sec) -*/ -define snat_det_get_timeouts_reply { - u32 context; - i32 retval; - u32 udp; - u32 tcp_established; - u32 tcp_transitory; - u32 icmp; -}; - -/** \brief Close CGNAT session by outside address and port - @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 - @param out_addr - outside IP address - @param out_port - outside port - @param ext_addr - external host address - @param ext_port - external host port -*/ -autoreply define snat_det_close_session_out { - u32 client_index; - u32 context; - u8 is_ip4; - u8 out_addr[16]; - u16 out_port; - u8 ext_addr[16]; - u16 ext_port; -}; - -/** \brief Close CGNAT session by inside address and port - @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 - @param in_addr - inside IP address - @param in_port - inside port - @param ext_addr - external host address - @param ext_port - external host port -*/ -autoreply define snat_det_close_session_in { - u32 client_index; - u32 context; - u8 is_ip4; - u8 in_addr[16]; - u16 in_port; - u8 ext_addr[16]; - u16 ext_port; -}; - -/** \brief Dump S-NAT deterministic sessions - @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 - @param user_addr - address of an inside user whose sessions to dump -*/ -define snat_det_session_dump { - u32 client_index; - u32 context; - u8 is_ip4; - u8 user_addr[16]; -}; - -/** \brief S-NAT deterministic sessions reply - @param context - sender context, to match reply w/ request - @param is_ip4 - 1 if address type is IPv4 - @param in_port - inside port - @param ext_addr - external host address - @param ext_port - external host port - @param out_port - outside NAT port - @param state - session state - @param expire - session expiration timestamp -*/ -define snat_det_session_details { - u32 client_index; - u32 context; - u8 is_ip4; - u16 in_port; - u8 ext_addr[16]; - u16 ext_port; - u16 out_port; - u8 state; - u32 expire; -}; - -/** \brief Add/delete address range to NAT64 pool - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param start_addr - start address of the range - @param end_addr - end address of the range - @param vrf_id - VRF id of tenant, ~0 means independent of VRF - @param is_add - 1 if add, 0 if delete -*/ -autoreply define nat64_add_del_pool_addr_range { - u32 client_index; - u32 context; - u8 start_addr[4]; - u8 end_addr[4]; - u32 vrf_id; - u8 is_add; -}; - -/** \brief Dump NAT64 pool addresses - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define nat64_pool_addr_dump { - u32 client_index; - u32 context; -}; - -/** \brief NAT64 pool address details response - @param context - sender context, to match reply w/ request - @param address - IPv4 address - @param vfr_id - VRF id of tenant, ~0 means independent of VRF -*/ -define nat64_pool_addr_details { - u32 context; - u8 address[4]; - u32 vrf_id; -}; - -/** \brief Enable/disable NAT64 feature on the interface - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - index of the interface - @param is_inside - 1 if inside, 0 if outside - @param is_add - 1 if add, 0 if delete -*/ -autoreply define nat64_add_del_interface { - u32 client_index; - u32 context; - u32 sw_if_index; - u8 is_inside; - u8 is_add; -}; - -/** \brief Dump interfaces with NAT64 feature - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define nat64_interface_dump { - u32 client_index; - u32 context; -}; - -/** \brief NAT64 interface details response - @param context - sender context, to match reply w/ request - @param is_inside - 1 if inside, 0 if outside - @param sw_if_index - index of the interface -*/ -define nat64_interface_details { - u32 context; - u8 is_inside; - u32 sw_if_index; -}; - -/** \brief Add/delete NAT64 static BIB entry - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param i_addr - inside IPv6 address - @param o_addr - outside IPv4 address - @param i_port - inside port number - @param o_port - outside port number - @param vrf_id - VRF id of tenant - @param proto - protocol number - @param is_add - 1 if add, 0 if delete -*/ - autoreply define nat64_add_del_static_bib { - u32 client_index; - u32 context; - u8 i_addr[16]; - u8 o_addr[4]; - u16 i_port; - u16 o_port; - u32 vrf_id; - u8 proto; - u8 is_add; -}; - -/** \brief Dump NAT64 BIB - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param proto - protocol of the BIB: 255 - all BIBs - 6 - TCP BIB - 17 - UDP BIB - 1/58 - ICMP BIB - otherwise - "unknown" protocol BIB -*/ -define nat64_bib_dump { - u32 client_index; - u32 context; - u8 proto; -}; - -/** \brief NAT64 BIB details response - @param context - sender context, to match reply w/ request - @param i_addr - inside IPv6 address - @param o_addr - outside IPv4 address - @param i_port - inside port number - @param o_port - outside port number - @param vrf_id - VRF id of tenant - @param proto - protocol number - @param is_static - 1 if static BIB entry, 0 if dynamic - @param ses_num - number of sessions associated with the BIB entry -*/ -define nat64_bib_details { - u32 context; - u8 i_addr[16]; - u8 o_addr[4]; - u16 i_port; - u16 o_port; - u32 vrf_id; - u8 proto; - u8 is_static; - u32 ses_num; -}; - -/** \brief Set values of timeouts for NAT64 (seconds, 0 = default) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param udp - UDP timeout (default 300sec) - @param icmp - ICMP timeout (default 60sec) - @param tcp_trans - TCP transitory timeout (default 240sec) - @param tcp_est - TCP established timeout (default 7440sec) - @param tcp_incoming_syn - TCP incoming SYN timeout (default 6sec) -*/ -autoreply define nat64_set_timeouts { - u32 client_index; - u32 context; - u32 udp; - u32 icmp; - u32 tcp_trans; - u32 tcp_est; - u32 tcp_incoming_syn; -}; - -/** \brief Get values of timeouts for NAT64 (seconds) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define nat64_get_timeouts { - u32 client_index; - u32 context; -}; - -/** \brief Get values of timeouts for NAT64 reply - @param context - sender context, to match reply w/ request - @param retval - return code - @param udp - UDP timeout - @param icmp - ICMP timeout - @param tcp_trans - TCP transitory timeout - @param tcp_est - TCP established timeout - @param tcp_incoming_syn - TCP incoming SYN timeout -*/ -define nat64_get_timeouts_reply { - u32 context; - i32 retval; - u32 udp; - u32 icmp; - u32 tcp_trans; - u32 tcp_est; - u32 tcp_incoming_syn; -}; - -/** \brief Dump NAT64 session table - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param proto - protocol of the session table: 255 - all STs - 6 - TCP ST - 17 - UDP ST - 1/58 - ICMP ST - otherwise - "unknown" proto ST -*/ -define nat64_st_dump { - u32 client_index; - u32 context; - u8 proto; -}; - -/** \brief NAT64 session table details response - @param context - sender context, to match reply w/ request - @param il_addr - inside IPv6 address of the local host - @param ol_addr - outside IPv4 address of the local host - @param il_port - inside port number id of the local host/inside ICMP id - @param ol_port - outside port number of the local host/outside ICMP id - @param il_addr - inside IPv6 address of the remote host - @param ol_addr - outside IPv4 address of the remote host - @param l_port - port number of the remote host (not used for ICMP) - @param vrf_id - VRF id of tenant - @param proto - protocol number -*/ -define nat64_st_details { - u32 context; - u8 il_addr[16]; - u8 ol_addr[4]; - u16 il_port; - u16 ol_port; - u8 ir_addr[16]; - u8 or_addr[4]; - u16 r_port; - u32 vrf_id; - u8 proto; -}; - -/** \brief Add/del NAT64 prefix - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param prefix - NAT64 prefix - @param prefix - NAT64 prefix length - @param vrf_id - VRF id of tenant - @param is_add - 1 if add, 0 if delete -*/ -autoreply define nat64_add_del_prefix { - u32 client_index; - u32 context; - u8 prefix[16]; - u8 prefix_len; - u32 vrf_id; - u8 is_add; -}; - -/** \brief Dump NAT64 prefix - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define nat64_prefix_dump { - u32 client_index; - u32 context; -}; - -/** \brief Dump NAT64 prefix details response - @param context - sender context, to match reply w/ request - @param prefix - NAT64 prefix - @param prefix - NAT64 prefix length - @param vrf_id - VRF id of tenant -*/ -define nat64_prefix_details { - u32 context; - u8 prefix[16]; - u8 prefix_len; - u32 vrf_id; -}; diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c deleted file mode 100644 index 315cec8a65b..00000000000 --- a/src/plugins/snat/snat.c +++ /dev/null @@ -1,2842 +0,0 @@ -/* - * snat.c - simple nat plugin - * - * Copyright (c) 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. - */ - -#include <vnet/vnet.h> -#include <vnet/ip/ip.h> -#include <vnet/ip/ip4.h> -#include <vnet/plugin/plugin.h> -#include <snat/snat.h> -#include <snat/snat_ipfix_logging.h> -#include <snat/snat_det.h> -#include <snat/nat64.h> -#include <vnet/fib/fib_table.h> -#include <vnet/fib/ip4_fib.h> - -#include <vpp/app/version.h> - -snat_main_t snat_main; - - -/* Hook up input features */ -VNET_FEATURE_INIT (ip4_snat_in2out, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-in2out", - .runs_before = VNET_FEATURES ("snat-out2in"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-out2in", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; -VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-det-in2out", - .runs_before = VNET_FEATURES ("snat-det-out2in"), -}; -VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-det-out2in", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; -VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-in2out-worker-handoff", - .runs_before = VNET_FEATURES ("snat-out2in-worker-handoff"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-out2in-worker-handoff", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; -VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-in2out-fast", - .runs_before = VNET_FEATURES ("snat-out2in-fast"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-out2in-fast", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; -VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = { - .arc_name = "ip4-unicast", - .node_name = "snat-hairpin-dst", - .runs_before = VNET_FEATURES ("ip4-lookup"), -}; - -/* Hook up output features */ -VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = { - .arc_name = "ip4-output", - .node_name = "snat-in2out-output", - .runs_before = VNET_FEATURES ("interface-output"), -}; -VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = { - .arc_name = "ip4-output", - .node_name = "snat-in2out-output-worker-handoff", - .runs_before = VNET_FEATURES ("interface-output"), -}; -VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = { - .arc_name = "ip4-output", - .node_name = "snat-hairpin-src", - .runs_before = VNET_FEATURES ("interface-output"), -}; - - -/* *INDENT-OFF* */ -VLIB_PLUGIN_REGISTER () = { - .version = VPP_BUILD_VER, - .description = "Network Address Translation", -}; -/* *INDENT-ON* */ - -/** - * @brief Add/del NAT address to FIB. - * - * Add the external NAT address to the FIB as receive entries. This ensures - * that VPP will reply to ARP for this address and we don't need to enable - * proxy ARP on the outside interface. - * - * @param addr IPv4 address. - * @param plen address prefix length - * @param sw_if_index Interface. - * @param is_add If 0 delete, otherwise add. - */ -void -snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index, - int is_add) -{ - fib_prefix_t prefix = { - .fp_len = p_len, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4.as_u32 = addr->as_u32, - }, - }; - u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index); - - if (is_add) - fib_table_entry_update_one_path(fib_index, - &prefix, - FIB_SOURCE_PLUGIN_HI, - (FIB_ENTRY_FLAG_CONNECTED | - FIB_ENTRY_FLAG_LOCAL | - FIB_ENTRY_FLAG_EXCLUSIVE), - DPO_PROTO_IP4, - NULL, - sw_if_index, - ~0, - 1, - NULL, - FIB_ROUTE_PATH_FLAG_NONE); - else - fib_table_entry_delete(fib_index, - &prefix, - FIB_SOURCE_PLUGIN_HI); -} - -void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id) -{ - snat_address_t * ap; - snat_interface_t *i; - - if (vrf_id != ~0) - sm->vrf_mode = 1; - - /* Check if address already exists */ - vec_foreach (ap, sm->addresses) - { - if (ap->addr.as_u32 == addr->as_u32) - return; - } - - vec_add2 (sm->addresses, ap, 1); - ap->addr = *addr; - if (vrf_id != ~0) - ap->fib_index = - fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id); - else - ap->fib_index = ~0; -#define _(N, i, n, s) \ - clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); - foreach_snat_protocol -#undef _ - - /* Add external address to FIB */ - pool_foreach (i, sm->interfaces, - ({ - if (i->is_inside) - continue; - - snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1); - break; - })); - pool_foreach (i, sm->output_feature_interfaces, - ({ - if (i->is_inside) - continue; - - snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1); - break; - })); -} - -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; -} - -void increment_v4_address (ip4_address_t * a) -{ - u32 v; - - v = clib_net_to_host_u32(a->as_u32) + 1; - a->as_u32 = clib_host_to_net_u32(v); -} - -static void -snat_add_static_mapping_when_resolved (snat_main_t * sm, - ip4_address_t l_addr, - u16 l_port, - u32 sw_if_index, - u16 e_port, - u32 vrf_id, - snat_protocol_t proto, - int addr_only, - int is_add) -{ - snat_static_map_resolve_t *rp; - - vec_add2 (sm->to_resolve, rp, 1); - rp->l_addr.as_u32 = l_addr.as_u32; - rp->l_port = l_port; - rp->sw_if_index = sw_if_index; - rp->e_port = e_port; - rp->vrf_id = vrf_id; - rp->proto = proto; - rp->addr_only = addr_only; - rp->is_add = is_add; -} - -/** - * @brief Add static mapping. - * - * Create static mapping between local addr+port and external addr+port. - * - * @param l_addr Local IPv4 address. - * @param e_addr External IPv4 address. - * @param l_port Local port number. - * @param e_port External port number. - * @param vrf_id VRF ID. - * @param addr_only If 0 address port and pair mapping, otherwise address only. - * @param sw_if_index External port instead of specific IP address. - * @param is_add If 0 delete static mapping, otherwise add. - * - * @returns - */ -int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, u32 vrf_id, int addr_only, - u32 sw_if_index, snat_protocol_t proto, int is_add) -{ - snat_main_t * sm = &snat_main; - snat_static_mapping_t *m; - snat_session_key_t m_key; - clib_bihash_kv_8_8_t kv, value; - snat_address_t *a = 0; - u32 fib_index = ~0; - uword * p; - snat_interface_t *interface; - int i; - - /* If the external address is a specific interface address */ - if (sw_if_index != ~0) - { - ip4_address_t * first_int_addr; - - /* Might be already set... */ - first_int_addr = ip4_interface_first_address - (sm->ip4_main, sw_if_index, 0 /* just want the address*/); - - /* DHCP resolution required? */ - if (first_int_addr == 0) - { - snat_add_static_mapping_when_resolved - (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto, - addr_only, is_add); - return 0; - } - else - e_addr.as_u32 = first_int_addr->as_u32; - } - - m_key.addr = e_addr; - m_key.port = addr_only ? 0 : e_port; - m_key.protocol = addr_only ? 0 : proto; - m_key.fib_index = sm->outside_fib_index; - kv.key = m_key.as_u64; - if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) - m = 0; - else - m = pool_elt_at_index (sm->static_mappings, value.value); - - if (is_add) - { - if (m) - return VNET_API_ERROR_VALUE_EXIST; - - /* Convert VRF id to FIB index */ - if (vrf_id != ~0) - { - p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id); - if (!p) - return VNET_API_ERROR_NO_SUCH_FIB; - fib_index = p[0]; - } - /* If not specified use inside VRF id from SNAT plugin startup config */ - else - { - fib_index = sm->inside_fib_index; - vrf_id = sm->inside_vrf_id; - } - - /* Find external address in allocated addresses and reserve port for - address and port pair mapping when dynamic translations enabled */ - if (!addr_only && !(sm->static_mapping_only)) - { - for (i = 0; i < vec_len (sm->addresses); i++) - { - if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) - { - a = sm->addresses + i; - /* External port must be unused */ - switch (proto) - { -#define _(N, j, n, s) \ - case SNAT_PROTOCOL_##N: \ - if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \ - return VNET_API_ERROR_INVALID_VALUE; \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \ - if (e_port > 1024) \ - a->busy_##n##_ports++; \ - break; - foreach_snat_protocol -#undef _ - default: - clib_warning("unknown_protocol"); - return VNET_API_ERROR_INVALID_VALUE_2; - } - break; - } - } - /* External address must be allocated */ - if (!a) - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - pool_get (sm->static_mappings, m); - memset (m, 0, sizeof (*m)); - m->local_addr = l_addr; - m->external_addr = e_addr; - m->addr_only = addr_only; - m->vrf_id = vrf_id; - m->fib_index = fib_index; - if (!addr_only) - { - m->local_port = l_port; - m->external_port = e_port; - m->proto = proto; - } - - m_key.addr = m->local_addr; - m_key.port = m->local_port; - m_key.protocol = m->proto; - m_key.fib_index = m->fib_index; - kv.key = m_key.as_u64; - kv.value = m - sm->static_mappings; - clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1); - - m_key.addr = m->external_addr; - m_key.port = m->external_port; - m_key.fib_index = sm->outside_fib_index; - kv.key = m_key.as_u64; - kv.value = m - sm->static_mappings; - clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1); - - /* Assign worker */ - if (sm->workers) - { - snat_user_key_t w_key0; - snat_worker_key_t w_key1; - - w_key0.addr = m->local_addr; - w_key0.fib_index = m->fib_index; - kv.key = w_key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value)) - { - kv.value = sm->first_worker_index + - sm->workers[sm->next_worker++ % vec_len (sm->workers)]; - - clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1); - } - else - { - kv.value = value.value; - } - - w_key1.addr = m->external_addr; - w_key1.port = clib_host_to_net_u16 (m->external_port); - w_key1.fib_index = sm->outside_fib_index; - kv.key = w_key1.as_u64; - clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1); - } - } - else - { - if (!m) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - /* Free external address port */ - if (!addr_only && !(sm->static_mapping_only)) - { - for (i = 0; i < vec_len (sm->addresses); i++) - { - if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) - { - a = sm->addresses + i; - switch (proto) - { -#define _(N, j, n, s) \ - case SNAT_PROTOCOL_##N: \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \ - if (e_port > 1024) \ - a->busy_##n##_ports--; \ - break; - foreach_snat_protocol -#undef _ - default: - clib_warning("unknown_protocol"); - return VNET_API_ERROR_INVALID_VALUE_2; - } - break; - } - } - } - - m_key.addr = m->local_addr; - m_key.port = m->local_port; - m_key.protocol = m->proto; - m_key.fib_index = m->fib_index; - kv.key = m_key.as_u64; - clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0); - - m_key.addr = m->external_addr; - m_key.port = m->external_port; - m_key.fib_index = sm->outside_fib_index; - kv.key = m_key.as_u64; - clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0); - - /* Delete session(s) for static mapping if exist */ - if (!(sm->static_mapping_only) || - (sm->static_mapping_only && sm->static_mapping_connection_tracking)) - { - snat_user_key_t u_key; - snat_user_t *u; - dlist_elt_t * head, * elt; - u32 elt_index, head_index, del_elt_index; - u32 ses_index; - u64 user_index; - snat_session_t * s; - snat_main_per_thread_data_t *tsm; - - u_key.addr = m->local_addr; - u_key.fib_index = m->fib_index; - kv.key = u_key.as_u64; - if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) - { - user_index = value.value; - if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value)) - tsm = vec_elt_at_index (sm->per_thread_data, value.value); - else - tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - u = pool_elt_at_index (tsm->users, user_index); - if (u->nstaticsessions) - { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tsm->list_pool, head_index); - elt_index = head->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - while (ses_index != ~0) - { - s = pool_elt_at_index (tsm->sessions, ses_index); - del_elt_index = elt_index; - elt_index = elt->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - - if (!addr_only) - { - if ((s->out2in.addr.as_u32 != e_addr.as_u32) && - (clib_net_to_host_u16 (s->out2in.port) != e_port)) - continue; - } - - if (snat_is_unk_proto_session (s)) - { - clib_bihash_kv_16_8_t up_kv; - snat_unk_proto_ses_key_t up_key; - up_key.l_addr = s->in2out.addr; - up_key.r_addr = s->ext_host_addr; - up_key.fib_index = s->in2out.fib_index; - up_key.proto = s->in2out.port; - up_key.rsvd[0] = up_key.rsvd[1] = up_key.rsvd[2] = 0; - up_kv.key[0] = up_key.as_u64[0]; - up_kv.key[1] = up_key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_unk_proto, - &up_kv, 0)) - clib_warning ("in2out key del failed"); - - up_key.l_addr = s->out2in.addr; - up_key.fib_index = s->out2in.fib_index; - up_kv.key[0] = up_key.as_u64[0]; - up_kv.key[1] = up_key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->out2in_unk_proto, - &up_kv, 0)) - clib_warning ("out2in key del failed"); - - goto delete; - } - /* log NAT event */ - snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32, - s->out2in.addr.as_u32, - s->in2out.protocol, - s->in2out.port, - s->out2in.port, - s->in2out.fib_index); - - value.key = s->in2out.as_u64; - if (clib_bihash_add_del_8_8 (&sm->in2out, &value, 0)) - clib_warning ("in2out key del failed"); - value.key = s->out2in.as_u64; - if (clib_bihash_add_del_8_8 (&sm->out2in, &value, 0)) - clib_warning ("out2in key del failed"); -delete: - pool_put (tsm->sessions, s); - - clib_dlist_remove (tsm->list_pool, del_elt_index); - pool_put_index (tsm->list_pool, del_elt_index); - u->nstaticsessions--; - - if (!addr_only) - break; - } - if (addr_only) - { - pool_put (tsm->users, u); - clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0); - } - } - } - } - - /* Delete static mapping from pool */ - pool_put (sm->static_mappings, m); - } - - if (!addr_only) - return 0; - - /* Add/delete external address to FIB */ - pool_foreach (interface, sm->interfaces, - ({ - if (interface->is_inside) - continue; - - snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add); - break; - })); - pool_foreach (interface, sm->output_feature_interfaces, - ({ - if (interface->is_inside) - continue; - - snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add); - break; - })); - - return 0; -} - -int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm) -{ - 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; - snat_main_per_thread_data_t *tsm; - snat_static_mapping_t *m; - snat_interface_t *interface; - 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; - - if (delete_sm) - { - pool_foreach (m, sm->static_mappings, - ({ - if (m->external_addr.as_u32 == addr.as_u32) - (void) snat_add_static_mapping (m->local_addr, m->external_addr, - m->local_port, m->external_port, - m->vrf_id, m->addr_only, ~0, - m->proto, 0); - })); - } - else - { - /* 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; - } - } - - if (a->fib_index != ~0) - fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4); - - /* Delete sessions using address */ - if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports) - { - vec_foreach (tsm, sm->per_thread_data) - { - pool_foreach (ses, tsm->sessions, ({ - if (ses->out2in.addr.as_u32 == addr.as_u32) - { - if (snat_is_unk_proto_session (ses)) - { - clib_bihash_kv_16_8_t up_kv; - snat_unk_proto_ses_key_t up_key; - up_key.l_addr = ses->in2out.addr; - up_key.r_addr = ses->ext_host_addr; - up_key.fib_index = ses->in2out.fib_index; - up_key.proto = ses->in2out.port; - up_key.rsvd[0] = up_key.rsvd[1] = up_key.rsvd[2] = 0; - up_kv.key[0] = up_key.as_u64[0]; - up_kv.key[1] = up_key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_unk_proto, - &up_kv, 0)) - clib_warning ("in2out key del failed"); - - up_key.l_addr = ses->out2in.addr; - up_key.fib_index = ses->out2in.fib_index; - up_kv.key[0] = up_key.as_u64[0]; - up_kv.key[1] = up_key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->out2in_unk_proto, - &up_kv, 0)) - clib_warning ("out2in key del failed"); - } - else - { - /* log NAT event */ - snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32, - ses->out2in.addr.as_u32, - ses->in2out.protocol, - ses->in2out.port, - ses->out2in.port, - ses->in2out.fib_index); - 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); - } - vec_add1 (ses_to_be_removed, ses - tsm->sessions); - clib_dlist_remove (tsm->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 (tsm->users, value.value); - u->nsessions--; - } - } - })); - - vec_foreach (ses_index, ses_to_be_removed) - pool_put_index (tsm->sessions, ses_index[0]); - - vec_free (ses_to_be_removed); - } - } - - vec_del1 (sm->addresses, i); - - /* Delete external address from FIB */ - pool_foreach (interface, sm->interfaces, - ({ - if (interface->is_inside) - continue; - - snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0); - break; - })); - pool_foreach (interface, sm->output_feature_interfaces, - ({ - if (interface->is_inside) - continue; - - snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0); - break; - })); - - return 0; -} - -int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) -{ - snat_main_t *sm = &snat_main; - snat_interface_t *i; - const char * feature_name; - snat_address_t * ap; - snat_static_mapping_t * m; - snat_det_map_t * dm; - - if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) - feature_name = is_inside ? "snat-in2out-fast" : "snat-out2in-fast"; - else - { - if (sm->num_workers > 1 && !sm->deterministic) - feature_name = is_inside ? "snat-in2out-worker-handoff" : "snat-out2in-worker-handoff"; - else if (sm->deterministic) - feature_name = is_inside ? "snat-det-in2out" : "snat-det-out2in"; - else - feature_name = is_inside ? "snat-in2out" : "snat-out2in"; - } - - vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, - !is_del, 0, 0); - - if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1) - sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0); - - if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1) - sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0); - - pool_foreach (i, sm->interfaces, - ({ - if (i->sw_if_index == sw_if_index) - { - if (is_del) - pool_put (sm->interfaces, i); - else - return VNET_API_ERROR_VALUE_EXIST; - - goto fib; - } - })); - - if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - pool_get (sm->interfaces, i); - i->sw_if_index = sw_if_index; - i->is_inside = is_inside; - - /* Add/delete external addresses to FIB */ -fib: - if (is_inside) - return 0; - - vec_foreach (ap, sm->addresses) - snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del); - - pool_foreach (m, sm->static_mappings, - ({ - if (!(m->addr_only)) - continue; - - snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del); - })); - - pool_foreach (dm, sm->det_maps, - ({ - snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del); - })); - - return 0; -} - -int snat_interface_add_del_output_feature (u32 sw_if_index, - u8 is_inside, - int is_del) -{ - snat_main_t *sm = &snat_main; - snat_interface_t *i; - snat_address_t * ap; - snat_static_mapping_t * m; - - if (sm->deterministic || - (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))) - return VNET_API_ERROR_UNSUPPORTED; - - if (is_inside) - { - vnet_feature_enable_disable ("ip4-unicast", "snat-hairpin-dst", - sw_if_index, !is_del, 0, 0); - vnet_feature_enable_disable ("ip4-output", "snat-hairpin-src", - sw_if_index, !is_del, 0, 0); - goto fq; - } - - if (sm->num_workers > 1) - { - vnet_feature_enable_disable ("ip4-unicast", "snat-out2in-worker-handoff", - sw_if_index, !is_del, 0, 0); - vnet_feature_enable_disable ("ip4-output", - "snat-in2out-output-worker-handoff", - sw_if_index, !is_del, 0, 0); - } - else - { - vnet_feature_enable_disable ("ip4-unicast", "snat-out2in", sw_if_index, - !is_del, 0, 0); - vnet_feature_enable_disable ("ip4-output", "snat-in2out-output", - sw_if_index, !is_del, 0, 0); - } - -fq: - if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1) - sm->fq_in2out_output_index = - vlib_frame_queue_main_init (sm->in2out_output_node_index, 0); - - if (sm->fq_out2in_index == ~0 && sm->num_workers > 1) - sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0); - - pool_foreach (i, sm->output_feature_interfaces, - ({ - if (i->sw_if_index == sw_if_index) - { - if (is_del) - pool_put (sm->output_feature_interfaces, i); - else - return VNET_API_ERROR_VALUE_EXIST; - - goto fib; - } - })); - - if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - pool_get (sm->output_feature_interfaces, i); - i->sw_if_index = sw_if_index; - i->is_inside = is_inside; - - /* Add/delete external addresses to FIB */ -fib: - if (is_inside) - return 0; - - vec_foreach (ap, sm->addresses) - snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del); - - pool_foreach (m, sm->static_mappings, - ({ - if (!(m->addr_only)) - continue; - - snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del); - })); - - return 0; -} - -int snat_set_workers (uword * bitmap) -{ - snat_main_t *sm = &snat_main; - int i, j = 0; - - if (sm->num_workers < 2) - return VNET_API_ERROR_FEATURE_DISABLED; - - if (clib_bitmap_last_set (bitmap) >= sm->num_workers) - return VNET_API_ERROR_INVALID_WORKER; - - vec_free (sm->workers); - clib_bitmap_foreach (i, bitmap, - ({ - vec_add1(sm->workers, i); - sm->per_thread_data[i].snat_thread_index = j; - j++; - })); - - sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers); - sm->num_snat_thread = _vec_len (sm->workers); - - return 0; -} - - -static void -snat_ip4_add_del_interface_address_cb (ip4_main_t * im, - uword opaque, - u32 sw_if_index, - ip4_address_t * address, - u32 address_length, - u32 if_address_index, - u32 is_delete); - -static clib_error_t * snat_init (vlib_main_t * vm) -{ - snat_main_t * sm = &snat_main; - clib_error_t * error = 0; - ip4_main_t * im = &ip4_main; - ip_lookup_main_t * lm = &im->lookup_main; - uword *p; - vlib_thread_registration_t *tr; - vlib_thread_main_t *tm = vlib_get_thread_main (); - uword *bitmap = 0; - u32 i; - ip4_add_del_interface_address_callback_t cb4; - - sm->vlib_main = vm; - sm->vnet_main = vnet_get_main(); - sm->ip4_main = im; - sm->ip4_lookup_main = lm; - sm->api_main = &api_main; - sm->first_worker_index = 0; - sm->next_worker = 0; - sm->num_workers = 0; - sm->num_snat_thread = 1; - sm->workers = 0; - sm->port_per_thread = 0xffff - 1024; - sm->fq_in2out_index = ~0; - sm->fq_out2in_index = ~0; - sm->udp_timeout = SNAT_UDP_TIMEOUT; - sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; - sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT; - sm->icmp_timeout = SNAT_ICMP_TIMEOUT; - - p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - if (p) - { - tr = (vlib_thread_registration_t *) p[0]; - if (tr) - { - sm->num_workers = tr->count; - sm->first_worker_index = tr->first_index; - } - } - - vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1); - - /* Use all available workers by default */ - if (sm->num_workers > 1) - { - for (i=0; i < sm->num_workers; i++) - bitmap = clib_bitmap_set (bitmap, i, 1); - snat_set_workers(bitmap); - clib_bitmap_free (bitmap); - } - else - { - sm->per_thread_data[0].snat_thread_index = 0; - } - - error = snat_api_init(vm, sm); - if (error) - return error; - - /* Set up the interface address add/del callback */ - cb4.function = snat_ip4_add_del_interface_address_cb; - cb4.function_opaque = 0; - - vec_add1 (im->add_del_interface_address_callbacks, cb4); - - /* Init IPFIX logging */ - snat_ipfix_logging_init(vm); - - error = nat64_init(vm); - - return error; -} - -VLIB_INIT_FUNCTION (snat_init); - -void snat_free_outside_address_and_port (snat_main_t * sm, - snat_session_key_t * k, - u32 address_index) -{ - snat_address_t *a; - u16 port_host_byte_order = clib_net_to_host_u16 (k->port); - - ASSERT (address_index < vec_len (sm->addresses)); - - a = sm->addresses + address_index; - - switch (k->protocol) - { -#define _(N, i, n, s) \ - case SNAT_PROTOCOL_##N: \ - ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \ - port_host_byte_order) == 1); \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \ - port_host_byte_order, 0); \ - a->busy_##n##_ports--; \ - break; - foreach_snat_protocol -#undef _ - default: - clib_warning("unknown_protocol"); - return; - } -} - -/** - * @brief Match SNAT static mapping. - * - * @param sm SNAT main. - * @param match Address and port to match. - * @param mapping External or local address and port of the matched mapping. - * @param by_external If 0 match by local address otherwise match by external - * address. - * @param is_addr_only If matched mapping is address only - * - * @returns 0 if match found otherwise 1. - */ -int snat_static_mapping_match (snat_main_t * sm, - snat_session_key_t match, - snat_session_key_t * mapping, - u8 by_external, - u8 *is_addr_only) -{ - clib_bihash_kv_8_8_t kv, value; - snat_static_mapping_t *m; - snat_session_key_t m_key; - clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local; - - if (by_external) - mapping_hash = &sm->static_mapping_by_external; - - m_key.addr = match.addr; - m_key.port = clib_net_to_host_u16 (match.port); - m_key.protocol = match.protocol; - m_key.fib_index = match.fib_index; - - kv.key = m_key.as_u64; - - if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) - { - /* Try address only mapping */ - m_key.port = 0; - m_key.protocol = 0; - kv.key = m_key.as_u64; - if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) - return 1; - } - - m = pool_elt_at_index (sm->static_mappings, value.value); - - if (by_external) - { - mapping->addr = m->local_addr; - /* Address only mapping doesn't change port */ - mapping->port = m->addr_only ? match.port - : clib_host_to_net_u16 (m->local_port); - mapping->fib_index = m->fib_index; - } - else - { - mapping->addr = m->external_addr; - /* Address only mapping doesn't change port */ - mapping->port = m->addr_only ? match.port - : clib_host_to_net_u16 (m->external_port); - mapping->fib_index = sm->outside_fib_index; - } - - if (PREDICT_FALSE(is_addr_only != 0)) - *is_addr_only = m->addr_only; - - return 0; -} - -static_always_inline u16 -snat_random_port (snat_main_t * sm, u16 min, u16 max) -{ - return min + random_u32 (&sm->random_seed) / - (random_u32_max() / (max - min + 1) + 1); -} - -int snat_alloc_outside_address_and_port (snat_main_t * sm, - u32 fib_index, - u32 thread_index, - snat_session_key_t * k, - u32 * address_indexp) -{ - int i; - snat_address_t *a; - u32 portnum; - - for (i = 0; i < vec_len (sm->addresses); i++) - { - a = sm->addresses + i; - if (sm->vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index) - continue; - switch (k->protocol) - { -#define _(N, j, n, s) \ - case SNAT_PROTOCOL_##N: \ - if (a->busy_##n##_ports < (sm->port_per_thread * sm->num_snat_thread)) \ - { \ - while (1) \ - { \ - portnum = (sm->port_per_thread * \ - sm->per_thread_data[thread_index].snat_thread_index) + \ - snat_random_port(sm, 0, sm->port_per_thread) + 1024; \ - if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \ - continue; \ - clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \ - a->busy_##n##_ports++; \ - k->addr = a->addr; \ - k->port = clib_host_to_net_u16(portnum); \ - *address_indexp = i; \ - return 0; \ - } \ - } \ - break; - foreach_snat_protocol -#undef _ - default: - clib_warning("unknown protocol"); - return 1; - } - - } - /* Totally out of translations to use... */ - snat_ipfix_logging_addresses_exhausted(0); - return 1; -} - - -static clib_error_t * -add_address_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - snat_main_t * sm = &snat_main; - ip4_address_t start_addr, end_addr, this_addr; - u32 start_host_order, end_host_order; - u32 vrf_id = ~0; - int i, count; - int is_add = 1; - int rv = 0; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - 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, "tenant-vrf %u", &vrf_id)) - ; - 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 - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (sm->static_mapping_only) - { - error = clib_error_return (0, "static mapping only mode"); - goto done; - } - - start_host_order = clib_host_to_net_u32 (start_addr.as_u32); - end_host_order = clib_host_to_net_u32 (end_addr.as_u32); - - if (end_host_order < start_host_order) - { - error = clib_error_return (0, "end address less than start address"); - goto done; - } - - count = (end_host_order - start_host_order) + 1; - - if (count > 1024) - clib_warning ("%U - %U, %d addresses...", - format_ip4_address, &start_addr, - format_ip4_address, &end_addr, - count); - - this_addr = start_addr; - - for (i = 0; i < count; i++) - { - if (is_add) - snat_add_address (sm, &this_addr, vrf_id); - else - rv = snat_del_address (sm, this_addr, 0); - - switch (rv) - { - case VNET_API_ERROR_NO_SUCH_ENTRY: - error = clib_error_return (0, "S-NAT address not exist."); - goto done; - case VNET_API_ERROR_UNSPECIFIED: - error = clib_error_return (0, "S-NAT address used in static mapping."); - goto done; - default: - break; - } - - increment_v4_address (&this_addr); - } - -done: - unformat_free (line_input); - - return error; -} - -VLIB_CLI_COMMAND (add_address_command, static) = { - .path = "snat add address", - .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] " - "[tenant-vrf <vrf-id>] [del]", - .function = add_address_command_fn, -}; - -static clib_error_t * -snat_feature_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - vnet_main_t * vnm = vnet_get_main(); - clib_error_t * error = 0; - u32 sw_if_index; - u32 * inside_sw_if_indices = 0; - u32 * outside_sw_if_indices = 0; - u8 is_output_feature = 0; - int is_del = 0; - int i; - - sw_if_index = ~0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "in %U", unformat_vnet_sw_interface, - vnm, &sw_if_index)) - vec_add1 (inside_sw_if_indices, sw_if_index); - else if (unformat (line_input, "out %U", unformat_vnet_sw_interface, - vnm, &sw_if_index)) - vec_add1 (outside_sw_if_indices, sw_if_index); - else if (unformat (line_input, "output-feature")) - is_output_feature = 1; - else if (unformat (line_input, "del")) - is_del = 1; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (vec_len (inside_sw_if_indices)) - { - for (i = 0; i < vec_len(inside_sw_if_indices); i++) - { - sw_if_index = inside_sw_if_indices[i]; - if (is_output_feature) - { - if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del)) - { - error = clib_error_return (0, "%s %U failed", - is_del ? "del" : "add", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, - sw_if_index)); - goto done; - } - } - else - { - if (snat_interface_add_del (sw_if_index, 1, is_del)) - { - error = clib_error_return (0, "%s %U failed", - is_del ? "del" : "add", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, - sw_if_index)); - goto done; - } - } - } - } - - if (vec_len (outside_sw_if_indices)) - { - for (i = 0; i < vec_len(outside_sw_if_indices); i++) - { - sw_if_index = outside_sw_if_indices[i]; - if (is_output_feature) - { - if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del)) - { - error = clib_error_return (0, "%s %U failed", - is_del ? "del" : "add", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, - sw_if_index)); - goto done; - } - } - else - { - if (snat_interface_add_del (sw_if_index, 0, is_del)) - { - error = clib_error_return (0, "%s %U failed", - is_del ? "del" : "add", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, - sw_if_index)); - goto done; - } - } - } - } - -done: - unformat_free (line_input); - vec_free (inside_sw_if_indices); - vec_free (outside_sw_if_indices); - - return error; -} - -VLIB_CLI_COMMAND (set_interface_snat_command, static) = { - .path = "set interface snat", - .function = snat_feature_command_fn, - .short_help = "set interface snat in <intfc> out <intfc> [output-feature] " - "[del]", -}; - -uword -unformat_snat_protocol (unformat_input_t * input, va_list * args) -{ - u32 *r = va_arg (*args, u32 *); - - if (0); -#define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N; - foreach_snat_protocol -#undef _ - else - return 0; - return 1; -} - -u8 * -format_snat_protocol (u8 * s, va_list * args) -{ - u32 i = va_arg (*args, u32); - u8 *t = 0; - - switch (i) - { -#define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break; - foreach_snat_protocol -#undef _ - default: - s = format (s, "unknown"); - return s; - } - s = format (s, "%s", t); - return s; -} - -static clib_error_t * -add_static_mapping_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t * error = 0; - ip4_address_t l_addr, e_addr; - u32 l_port = 0, e_port = 0, vrf_id = ~0; - int is_add = 1; - int addr_only = 1; - u32 sw_if_index = ~0; - vnet_main_t * vnm = vnet_get_main(); - int rv; - snat_protocol_t proto; - u8 proto_set = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr, - &l_port)) - addr_only = 0; - else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr)) - ; - else if (unformat (line_input, "external %U %u", unformat_ip4_address, - &e_addr, &e_port)) - addr_only = 0; - else if (unformat (line_input, "external %U", unformat_ip4_address, - &e_addr)) - ; - else if (unformat (line_input, "external %U %u", - unformat_vnet_sw_interface, vnm, &sw_if_index, - &e_port)) - addr_only = 0; - - else if (unformat (line_input, "external %U", - unformat_vnet_sw_interface, vnm, &sw_if_index)) - ; - else if (unformat (line_input, "vrf %u", &vrf_id)) - ; - else if (unformat (line_input, "%U", unformat_snat_protocol, &proto)) - proto_set = 1; - else if (unformat (line_input, "del")) - is_add = 0; - else - { - error = clib_error_return (0, "unknown input: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (!addr_only && !proto_set) - { - error = clib_error_return (0, "missing protocol"); - goto done; - } - - rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port, - vrf_id, addr_only, sw_if_index, proto, is_add); - - switch (rv) - { - case VNET_API_ERROR_INVALID_VALUE: - error = clib_error_return (0, "External port already in use."); - goto done; - case VNET_API_ERROR_NO_SUCH_ENTRY: - if (is_add) - error = clib_error_return (0, "External addres must be allocated."); - else - error = clib_error_return (0, "Mapping not exist."); - goto done; - case VNET_API_ERROR_NO_SUCH_FIB: - error = clib_error_return (0, "No such VRF id."); - goto done; - case VNET_API_ERROR_VALUE_EXIST: - error = clib_error_return (0, "Mapping already exist."); - goto done; - default: - break; - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat add static mapping} - * Static mapping allows hosts on the external network to initiate connection - * to to the local network host. - * To create static mapping between local host address 10.0.0.3 port 6303 and - * external address 4.4.4.4 port 3606 for TCP protocol use: - * vpp# snat add static mapping local tcp 10.0.0.3 6303 external 4.4.4.4 3606 - * If not runnig "static mapping only" S-NAT plugin mode use before: - * vpp# snat add address 4.4.4.4 - * To create static mapping between local and external address use: - * vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4 - * @cliexend -?*/ -VLIB_CLI_COMMAND (add_static_mapping_command, static) = { - .path = "snat add static mapping", - .function = add_static_mapping_command_fn, - .short_help = - "snat add static mapping local tcp|udp|icmp <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]", -}; - -static clib_error_t * -set_workers_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - uword *bitmap = 0; - int rv = 0; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap)) - ; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (bitmap == 0) - { - error = clib_error_return (0, "List of workers must be specified."); - goto done; - } - - rv = snat_set_workers(bitmap); - - clib_bitmap_free (bitmap); - - switch (rv) - { - case VNET_API_ERROR_INVALID_WORKER: - error = clib_error_return (0, "Invalid worker(s)."); - goto done; - case VNET_API_ERROR_FEATURE_DISABLED: - error = clib_error_return (0, - "Supported only if 2 or more workes available."); - goto done; - default: - break; - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{set snat workers} - * Set SNAT workers if 2 or more workers available, use: - * vpp# set snat workers 0-2,5 - * @cliexend -?*/ -VLIB_CLI_COMMAND (set_workers_command, static) = { - .path = "set snat workers", - .function = set_workers_command_fn, - .short_help = - "set snat workers <workers-list>", -}; - -static clib_error_t * -snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - u32 domain_id = 0; - u32 src_port = 0; - u8 enable = 1; - int rv = 0; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "domain %d", &domain_id)) - ; - else if (unformat (line_input, "src-port %d", &src_port)) - ; - else if (unformat (line_input, "disable")) - enable = 0; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port); - - if (rv) - { - error = clib_error_return (0, "ipfix logging enable failed"); - goto done; - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat ipfix logging} - * To enable SNAT IPFIX logging use: - * vpp# snat ipfix logging - * To set IPFIX exporter use: - * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1 - * @cliexend -?*/ -VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = { - .path = "snat ipfix logging", - .function = snat_ipfix_logging_enable_disable_command_fn, - .short_help = "snat ipfix logging [domain <domain-id>] [src-port <port>] [disable]", -}; - -static u32 -snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0) -{ - snat_main_t *sm = &snat_main; - snat_user_key_t key0; - clib_bihash_kv_8_8_t kv0, value0; - u32 next_worker_index = 0; - - key0.addr = ip0->src_address; - key0.fib_index = rx_fib_index0; - - kv0.key = key0.as_u64; - - /* Ever heard of of the "user" before? */ - if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv0, &value0)) - { - /* No, assign next available worker (RR) */ - next_worker_index = sm->first_worker_index; - if (vec_len (sm->workers)) - { - next_worker_index += - sm->workers[sm->next_worker++ % _vec_len (sm->workers)]; - } - - /* add non-traslated packets worker lookup */ - kv0.value = next_worker_index; - clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); - } - else - next_worker_index = value0.value; - - return next_worker_index; -} - -static u32 -snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0) -{ - snat_main_t *sm = &snat_main; - snat_worker_key_t key0; - clib_bihash_kv_8_8_t kv0, value0; - udp_header_t * udp0; - u32 next_worker_index = 0; - - udp0 = ip4_next_header (ip0); - - key0.addr = ip0->dst_address; - key0.port = udp0->dst_port; - key0.fib_index = rx_fib_index0; - - if (PREDICT_FALSE(ip0->protocol == IP_PROTOCOL_ICMP)) - { - icmp46_header_t * icmp0 = (icmp46_header_t *) udp0; - icmp_echo_header_t *echo0 = (icmp_echo_header_t *)(icmp0+1); - key0.port = echo0->identifier; - } - - kv0.key = key0.as_u64; - - /* Ever heard of of the "user" before? */ - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) - { - key0.port = 0; - kv0.key = key0.as_u64; - - if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0)) - { - /* No, assign next available worker (RR) */ - next_worker_index = sm->first_worker_index; - if (vec_len (sm->workers)) - { - next_worker_index += - sm->workers[sm->next_worker++ % _vec_len (sm->workers)]; - } - } - else - { - /* Static mapping without port */ - next_worker_index = value0.value; - } - - /* Add to translated packets worker lookup */ - kv0.value = next_worker_index; - clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1); - } - else - next_worker_index = value0.value; - - return next_worker_index; -} - -static clib_error_t * -snat_config (vlib_main_t * vm, unformat_input_t * input) -{ - snat_main_t * sm = &snat_main; - u32 translation_buckets = 1024; - u32 translation_memory_size = 128<<20; - u32 user_buckets = 128; - u32 user_memory_size = 64<<20; - u32 max_translations_per_user = 100; - u32 outside_vrf_id = 0; - u32 inside_vrf_id = 0; - u32 static_mapping_buckets = 1024; - u32 static_mapping_memory_size = 64<<20; - u8 static_mapping_only = 0; - u8 static_mapping_connection_tracking = 0; - - sm->deterministic = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "translation hash buckets %d", &translation_buckets)) - ; - else if (unformat (input, "translation hash memory %d", - &translation_memory_size)); - else if (unformat (input, "user hash buckets %d", &user_buckets)) - ; - else if (unformat (input, "user hash memory %d", - &user_memory_size)) - ; - else if (unformat (input, "max translations per user %d", - &max_translations_per_user)) - ; - else if (unformat (input, "outside VRF id %d", - &outside_vrf_id)) - ; - else if (unformat (input, "inside VRF id %d", - &inside_vrf_id)) - ; - else if (unformat (input, "static mapping only")) - { - static_mapping_only = 1; - if (unformat (input, "connection tracking")) - static_mapping_connection_tracking = 1; - } - else if (unformat (input, "deterministic")) - sm->deterministic = 1; - else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); - } - - /* for show commands, etc. */ - sm->translation_buckets = translation_buckets; - sm->translation_memory_size = translation_memory_size; - sm->user_buckets = user_buckets; - sm->user_memory_size = user_memory_size; - sm->max_translations_per_user = max_translations_per_user; - sm->outside_vrf_id = outside_vrf_id; - sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, - outside_vrf_id); - sm->inside_vrf_id = inside_vrf_id; - sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, - inside_vrf_id); - sm->static_mapping_only = static_mapping_only; - sm->static_mapping_connection_tracking = static_mapping_connection_tracking; - - if (sm->deterministic) - { - sm->in2out_node_index = snat_det_in2out_node.index; - sm->in2out_output_node_index = ~0; - sm->out2in_node_index = snat_det_out2in_node.index; - sm->icmp_match_in2out_cb = icmp_match_in2out_det; - sm->icmp_match_out2in_cb = icmp_match_out2in_det; - } - else - { - sm->worker_in2out_cb = snat_get_worker_in2out_cb; - sm->worker_out2in_cb = snat_get_worker_out2in_cb; - sm->in2out_node_index = snat_in2out_node.index; - sm->in2out_output_node_index = snat_in2out_output_node.index; - sm->out2in_node_index = snat_out2in_node.index; - if (!static_mapping_only || - (static_mapping_only && static_mapping_connection_tracking)) - { - sm->icmp_match_in2out_cb = icmp_match_in2out_slow; - sm->icmp_match_out2in_cb = icmp_match_out2in_slow; - - clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets, - user_memory_size); - - clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets, - user_memory_size); - - clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets, - translation_memory_size); - - clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets, - translation_memory_size); - - clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets, - user_memory_size); - - clib_bihash_init_16_8 (&sm->in2out_unk_proto, "in2out-unk-proto", - translation_buckets, translation_memory_size); - - clib_bihash_init_16_8 (&sm->out2in_unk_proto, "out2in-unk-proto", - translation_buckets, translation_memory_size); - } - else - { - sm->icmp_match_in2out_cb = icmp_match_in2out_fast; - sm->icmp_match_out2in_cb = icmp_match_out2in_fast; - } - clib_bihash_init_8_8 (&sm->static_mapping_by_local, - "static_mapping_by_local", static_mapping_buckets, - static_mapping_memory_size); - - clib_bihash_init_8_8 (&sm->static_mapping_by_external, - "static_mapping_by_external", static_mapping_buckets, - static_mapping_memory_size); - } - - return 0; -} - -VLIB_CONFIG_FUNCTION (snat_config, "snat"); - -u8 * format_snat_session_state (u8 * s, va_list * args) -{ - u32 i = va_arg (*args, u32); - u8 *t = 0; - - switch (i) - { -#define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break; - foreach_snat_session_state -#undef _ - default: - t = format (t, "unknown"); - } - s = format (s, "%s", t); - return s; -} - -u8 * format_snat_key (u8 * s, va_list * args) -{ - snat_session_key_t * key = va_arg (*args, snat_session_key_t *); - char * protocol_string = "unknown"; - static char *protocol_strings[] = { - "UDP", - "TCP", - "ICMP", - }; - - if (key->protocol < ARRAY_LEN(protocol_strings)) - protocol_string = protocol_strings[key->protocol]; - - s = format (s, "%U proto %s port %d fib %d", - format_ip4_address, &key->addr, protocol_string, - clib_net_to_host_u16 (key->port), key->fib_index); - return s; -} - -u8 * format_snat_session (u8 * s, va_list * args) -{ - snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *); - snat_session_t * sess = va_arg (*args, snat_session_t *); - - if (snat_is_unk_proto_session (sess)) - { - s = format (s, " i2o %U proto %u fib %u\n", - format_ip4_address, &sess->in2out.addr, sess->in2out.port, - sess->in2out.fib_index); - s = format (s, " o2i %U proto %u fib %u\n", - format_ip4_address, &sess->out2in.addr, sess->out2in.port, - sess->out2in.fib_index); - } - else - { - s = format (s, " i2o %U\n", format_snat_key, &sess->in2out); - s = format (s, " o2i %U\n", format_snat_key, &sess->out2in); - } - s = format (s, " last heard %.2f\n", sess->last_heard); - s = format (s, " total pkts %d, total bytes %lld\n", - sess->total_pkts, sess->total_bytes); - if (snat_is_session_static (sess)) - s = format (s, " static translation\n"); - else - s = format (s, " dynamic translation\n"); - - return s; -} - -u8 * format_snat_user (u8 * s, va_list * args) -{ - snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *); - snat_user_t * u = va_arg (*args, snat_user_t *); - int verbose = va_arg (*args, int); - dlist_elt_t * head, * elt; - u32 elt_index, head_index; - u32 session_index; - snat_session_t * sess; - - s = format (s, "%U: %d dynamic translations, %d static translations\n", - format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions); - - if (verbose == 0) - return s; - - if (u->nsessions || u->nstaticsessions) - { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (sm->list_pool, head_index); - - elt_index = head->next; - elt = pool_elt_at_index (sm->list_pool, elt_index); - session_index = elt->value; - - while (session_index != ~0) - { - sess = pool_elt_at_index (sm->sessions, session_index); - - s = format (s, " %U\n", format_snat_session, sm, sess); - - elt_index = elt->next; - elt = pool_elt_at_index (sm->list_pool, elt_index); - session_index = elt->value; - } - } - - return s; -} - -u8 * format_snat_static_mapping (u8 * s, va_list * args) -{ - snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *); - - if (m->addr_only) - s = format (s, "local %U external %U vrf %d", - format_ip4_address, &m->local_addr, - format_ip4_address, &m->external_addr, - m->vrf_id); - else - s = format (s, "%U local %U:%d external %U:%d vrf %d", - format_snat_protocol, m->proto, - format_ip4_address, &m->local_addr, m->local_port, - format_ip4_address, &m->external_addr, m->external_port, - m->vrf_id); - - return s; -} - -u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args) -{ - snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *); - vnet_main_t *vnm = vnet_get_main(); - - if (m->addr_only) - s = format (s, "local %U external %U vrf %d", - format_ip4_address, &m->l_addr, - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, m->sw_if_index), - m->vrf_id); - else - s = format (s, "%U local %U:%d external %U:%d vrf %d", - format_snat_protocol, m->proto, - format_ip4_address, &m->l_addr, m->l_port, - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port, - m->vrf_id); - - return s; -} - -u8 * format_det_map_ses (u8 * s, va_list * args) -{ - snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *); - ip4_address_t in_addr, out_addr; - u32 in_offset, out_offset; - snat_det_session_t * ses = va_arg (*args, snat_det_session_t *); - u32 * i = va_arg (*args, u32 *); - - u32 user_index = *i / SNAT_DET_SES_PER_USER; - in_addr.as_u32 = clib_host_to_net_u32 ( - clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index); - in_offset = clib_net_to_host_u32(in_addr.as_u32) - - clib_net_to_host_u32(det_map->in_addr.as_u32); - out_offset = in_offset / det_map->sharing_ratio; - out_addr.as_u32 = clib_host_to_net_u32( - clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset); - s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n", - format_ip4_address, &in_addr, - clib_net_to_host_u16 (ses->in_port), - format_ip4_address, &out_addr, - clib_net_to_host_u16 (ses->out.out_port), - format_ip4_address, &ses->out.ext_host_addr, - clib_net_to_host_u16 (ses->out.ext_host_port), - format_snat_session_state, ses->state, - ses->expire); - - return s; -} - -static clib_error_t * -show_snat_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - int verbose = 0; - snat_main_t * sm = &snat_main; - snat_user_t * u; - snat_static_mapping_t *m; - snat_interface_t *i; - snat_address_t * ap; - vnet_main_t *vnm = vnet_get_main(); - snat_main_per_thread_data_t *tsm; - u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index; - uword j = 0; - snat_static_map_resolve_t *rp; - snat_det_map_t * dm; - snat_det_session_t * ses; - - if (unformat (input, "detail")) - verbose = 1; - else if (unformat (input, "verbose")) - verbose = 2; - - if (sm->static_mapping_only) - { - if (sm->static_mapping_connection_tracking) - vlib_cli_output (vm, "SNAT mode: static mapping only connection " - "tracking"); - else - vlib_cli_output (vm, "SNAT mode: static mapping only"); - } - else if (sm->deterministic) - { - vlib_cli_output (vm, "SNAT mode: deterministic mapping"); - } - else - { - vlib_cli_output (vm, "SNAT mode: dynamic translations enabled"); - } - - if (verbose > 0) - { - pool_foreach (i, sm->interfaces, - ({ - vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, i->sw_if_index), - i->is_inside ? "in" : "out"); - })); - - pool_foreach (i, sm->output_feature_interfaces, - ({ - vlib_cli_output (vm, "%U output-feature %s", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, i->sw_if_index), - i->is_inside ? "in" : "out"); - })); - - if (vec_len (sm->auto_add_sw_if_indices)) - { - vlib_cli_output (vm, "SNAT pool addresses interfaces:"); - vec_foreach (sw_if_index, sm->auto_add_sw_if_indices) - { - vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, *sw_if_index)); - } - } - - vec_foreach (ap, sm->addresses) - { - vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); - if (ap->fib_index != ~0) - vlib_cli_output (vm, " tenant VRF: %u", - ip4_fib_get(ap->fib_index)->table_id); - else - vlib_cli_output (vm, " tenant VRF independent"); -#define _(N, i, n, s) \ - vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); - foreach_snat_protocol -#undef _ - } - } - - if (sm->num_workers > 1) - { - vlib_cli_output (vm, "%d workers", vec_len (sm->workers)); - if (verbose > 0) - { - vec_foreach (worker, sm->workers) - { - vlib_worker_thread_t *w = - vlib_worker_threads + *worker + sm->first_worker_index; - vlib_cli_output (vm, " %s", w->name); - } - } - } - - if (sm->deterministic) - { - vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout); - vlib_cli_output (vm, "tcp-established timeout: %dsec", - sm->tcp_established_timeout); - vlib_cli_output (vm, "tcp-transitory timeout: %dsec", - sm->tcp_transitory_timeout); - vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout); - vlib_cli_output (vm, "%d deterministic mappings", - pool_elts (sm->det_maps)); - if (verbose > 0) - { - pool_foreach (dm, sm->det_maps, - ({ - vlib_cli_output (vm, "in %U/%d out %U/%d\n", - format_ip4_address, &dm->in_addr, dm->in_plen, - format_ip4_address, &dm->out_addr, dm->out_plen); - vlib_cli_output (vm, " outside address sharing ratio: %d\n", - dm->sharing_ratio); - vlib_cli_output (vm, " number of ports per inside host: %d\n", - dm->ports_per_host); - vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num); - if (verbose > 1) - { - vec_foreach_index (j, dm->sessions) - { - ses = vec_elt_at_index (dm->sessions, j); - if (ses->in_port) - vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses, - &j); - } - } - })); - } - } - else - { - if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) - { - vlib_cli_output (vm, "%d static mappings", - pool_elts (sm->static_mappings)); - - if (verbose > 0) - { - pool_foreach (m, sm->static_mappings, - ({ - vlib_cli_output (vm, "%U", format_snat_static_mapping, m); - })); - } - } - else - { - vec_foreach (tsm, sm->per_thread_data) - { - users_num += pool_elts (tsm->users); - sessions_num += pool_elts (tsm->sessions); - } - - vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions," - " %d static mappings", - users_num, - vec_len (sm->addresses), - sessions_num, - pool_elts (sm->static_mappings)); - - if (verbose > 0) - { - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out, - verbose - 1); - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in, - verbose - 1); - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in, - verbose - 1); - vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out, - verbose - 1); - vec_foreach_index (j, sm->per_thread_data) - { - tsm = vec_elt_at_index (sm->per_thread_data, j); - - if (pool_elts (tsm->users) == 0) - continue; - - vlib_worker_thread_t *w = vlib_worker_threads + j; - vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name, - w->lcore_id); - vlib_cli_output (vm, " %d list pool elements", - pool_elts (tsm->list_pool)); - - pool_foreach (u, tsm->users, - ({ - vlib_cli_output (vm, " %U", format_snat_user, tsm, u, - verbose - 1); - })); - } - - if (pool_elts (sm->static_mappings)) - { - vlib_cli_output (vm, "static mappings:"); - pool_foreach (m, sm->static_mappings, - ({ - vlib_cli_output (vm, "%U", format_snat_static_mapping, m); - })); - for (j = 0; j < vec_len (sm->to_resolve); j++) - { - rp = sm->to_resolve + j; - vlib_cli_output (vm, "%U", - format_snat_static_map_to_resolve, rp); - } - } - } - } - } - return 0; -} - -VLIB_CLI_COMMAND (show_snat_command, static) = { - .path = "show snat", - .short_help = "show snat", - .function = show_snat_command_fn, -}; - - -static void -snat_ip4_add_del_interface_address_cb (ip4_main_t * im, - uword opaque, - u32 sw_if_index, - ip4_address_t * address, - u32 address_length, - u32 if_address_index, - u32 is_delete) -{ - snat_main_t *sm = &snat_main; - snat_static_map_resolve_t *rp; - u32 *indices_to_delete = 0; - int i, j; - int rv; - - for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++) - { - if (sw_if_index == sm->auto_add_sw_if_indices[i]) - { - if (!is_delete) - { - /* Don't trip over lease renewal, static config */ - for (j = 0; j < vec_len(sm->addresses); j++) - if (sm->addresses[j].addr.as_u32 == address->as_u32) - return; - - snat_add_address (sm, address, ~0); - /* Scan static map resolution vector */ - for (j = 0; j < vec_len (sm->to_resolve); j++) - { - rp = sm->to_resolve + j; - /* On this interface? */ - if (rp->sw_if_index == sw_if_index) - { - /* Add the static mapping */ - rv = snat_add_static_mapping (rp->l_addr, - address[0], - rp->l_port, - rp->e_port, - rp->vrf_id, - rp->addr_only, - ~0 /* sw_if_index */, - rp->proto, - rp->is_add); - if (rv) - clib_warning ("snat_add_static_mapping returned %d", - rv); - vec_add1 (indices_to_delete, j); - } - } - /* If we resolved any of the outstanding static mappings */ - if (vec_len(indices_to_delete)) - { - /* Delete them */ - for (j = vec_len(indices_to_delete)-1; j >= 0; j--) - vec_delete(sm->to_resolve, 1, j); - vec_free(indices_to_delete); - } - return; - } - else - { - (void) snat_del_address(sm, address[0], 1); - return; - } - } - } -} - - -int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del) -{ - ip4_main_t * ip4_main = sm->ip4_main; - ip4_address_t * first_int_addr; - snat_static_map_resolve_t *rp; - u32 *indices_to_delete = 0; - int i, j; - - first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, - 0 /* just want the address*/); - - for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++) - { - if (sm->auto_add_sw_if_indices[i] == sw_if_index) - { - if (is_del) - { - /* if have address remove it */ - if (first_int_addr) - (void) snat_del_address (sm, first_int_addr[0], 1); - else - { - for (j = 0; j < vec_len (sm->to_resolve); j++) - { - rp = sm->to_resolve + j; - if (rp->sw_if_index == sw_if_index) - vec_add1 (indices_to_delete, j); - } - if (vec_len(indices_to_delete)) - { - for (j = vec_len(indices_to_delete)-1; j >= 0; j--) - vec_del1(sm->to_resolve, j); - vec_free(indices_to_delete); - } - } - vec_del1(sm->auto_add_sw_if_indices, i); - } - else - return VNET_API_ERROR_VALUE_EXIST; - - return 0; - } - } - - if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - /* add to the auto-address list */ - vec_add1(sm->auto_add_sw_if_indices, sw_if_index); - - /* If the address is already bound - or static - add it now */ - if (first_int_addr) - snat_add_address (sm, first_int_addr, ~0); - - return 0; -} - -static clib_error_t * -snat_add_interface_address_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - snat_main_t *sm = &snat_main; - unformat_input_t _line_input, *line_input = &_line_input; - u32 sw_if_index; - int rv; - int is_del = 0; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U", unformat_vnet_sw_interface, - sm->vnet_main, &sw_if_index)) - ; - else if (unformat (line_input, "del")) - is_del = 1; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - rv = snat_add_interface_address (sm, sw_if_index, is_del); - - switch (rv) - { - case 0: - break; - - default: - error = clib_error_return (0, "snat_add_interface_address returned %d", - rv); - goto done; - } - -done: - unformat_free (line_input); - - return error; -} - -VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = { - .path = "snat add interface address", - .short_help = "snat add interface address <interface> [del]", - .function = snat_add_interface_address_command_fn, -}; - -static clib_error_t * -snat_det_map_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - snat_main_t *sm = &snat_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t in_addr, out_addr; - u32 in_plen, out_plen; - int is_add = 1, rv; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen)) - ; - else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen)) - ; - else if (unformat (line_input, "del")) - is_add = 0; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - unformat_free (line_input); - - rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen, - is_add); - - if (rv) - { - error = clib_error_return (0, "snat_det_add_map return %d", rv); - goto done; - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat deterministic add} - * Create bijective mapping of inside address to outside address and port range - * pairs, with the purpose of enabling deterministic NAT to reduce logging in - * CGN deployments. - * To create deterministic mapping between inside network 10.0.0.0/18 and - * outside network 1.1.1.0/30 use: - * # vpp# snat deterministic add in 10.0.0.0/18 out 1.1.1.0/30 - * @cliexend -?*/ -VLIB_CLI_COMMAND (snat_det_map_command, static) = { - .path = "snat deterministic add", - .short_help = "snat deterministic add in <addr>/<plen> out <addr>/<plen> [del]", - .function = snat_det_map_command_fn, -}; - -static clib_error_t * -snat_det_forward_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - snat_main_t *sm = &snat_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t in_addr, out_addr; - u16 lo_port; - snat_det_map_t * dm; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (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, &in_addr)) - ; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - unformat_free (line_input); - - dm = snat_det_map_by_user(sm, &in_addr); - if (!dm) - vlib_cli_output (vm, "no match"); - else - { - snat_det_forward (dm, &in_addr, &out_addr, &lo_port); - vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr, - lo_port, lo_port + dm->ports_per_host - 1); - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat deterministic forward} - * Return outside address and port range from inside address for deterministic - * NAT. - * To obtain outside address and port of inside host use: - * vpp# snat deterministic forward 10.0.0.2 - * 1.1.1.0:<1054-1068> - * @cliexend -?*/ -VLIB_CLI_COMMAND (snat_det_forward_command, static) = { - .path = "snat deterministic forward", - .short_help = "snat deterministic forward <addr>", - .function = snat_det_forward_command_fn, -}; - -static clib_error_t * -snat_det_reverse_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - snat_main_t *sm = &snat_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t in_addr, out_addr; - u32 out_port; - snat_det_map_t * dm; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port)) - ; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - } - } - - unformat_free (line_input); - - if (out_port < 1024 || out_port > 65535) - { - error = clib_error_return (0, "wrong port, must be <1024-65535>"); - goto done; - } - - dm = snat_det_map_by_out(sm, &out_addr); - if (!dm) - vlib_cli_output (vm, "no match"); - else - { - snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr); - vlib_cli_output (vm, "%U", format_ip4_address, &in_addr); - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat deterministic reverse} - * Return inside address from outside address and port for deterministic NAT. - * To obtain inside host address from outside address and port use: - * #vpp snat deterministic reverse 1.1.1.1:1276 - * 10.0.16.16 - * @cliexend -?*/ -VLIB_CLI_COMMAND (snat_det_reverse_command, static) = { - .path = "snat deterministic reverse", - .short_help = "snat deterministic reverse <addr>:<port>", - .function = snat_det_reverse_command_fn, -}; - -static clib_error_t * -set_timeout_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - snat_main_t *sm = &snat_main; - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "udp %u", &sm->udp_timeout)) - ; - else if (unformat (line_input, "tcp-established %u", - &sm->tcp_established_timeout)) - ; - else if (unformat (line_input, "tcp-transitory %u", - &sm->tcp_transitory_timeout)) - ; - else if (unformat (line_input, "icmp %u", &sm->icmp_timeout)) - ; - else if (unformat (line_input, "reset")) - { - sm->udp_timeout = SNAT_UDP_TIMEOUT; - sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; - sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT; - sm->icmp_timeout = SNAT_ICMP_TIMEOUT; - } - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - unformat_free (line_input); - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{set snat deterministic timeout} - * Set values of timeouts for deterministic NAT (in seconds), use: - * vpp# set snat deterministic timeout udp 120 tcp-established 7500 - * tcp-transitory 250 icmp 90 - * To reset default values use: - * vpp# set snat deterministic timeout reset - * @cliexend -?*/ -VLIB_CLI_COMMAND (set_timeout_command, static) = { - .path = "set snat deterministic timeout", - .function = set_timeout_command_fn, - .short_help = - "set snat deterministic timeout [udp <sec> | tcp-established <sec> " - "tcp-transitory <sec> | icmp <sec> | reset]", -}; - -static clib_error_t * -snat_det_close_session_out_fn (vlib_main_t *vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - snat_main_t *sm = &snat_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t out_addr, ext_addr, in_addr; - u16 out_port, ext_port; - snat_det_map_t * dm; - snat_det_session_t * ses; - snat_det_out_key_t key; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U:%d %U:%d", - unformat_ip4_address, &out_addr, &out_port, - unformat_ip4_address, &ext_addr, &ext_port)) - ; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - unformat_free (line_input); - - dm = snat_det_map_by_out(sm, &out_addr); - if (!dm) - vlib_cli_output (vm, "no match"); - else - { - snat_det_reverse(dm, &ext_addr, out_port, &in_addr); - key.ext_host_addr = out_addr; - key.ext_host_port = ntohs(ext_port); - key.out_port = ntohs(out_port); - ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64); - if (!ses) - vlib_cli_output (vm, "no match"); - else - snat_det_ses_close(dm, ses); - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat deterministic close session out} - * Close session using outside ip address and port - * and external ip address and port, use: - * vpp# snat deterministic close session out 1.1.1.1:1276 2.2.2.2:2387 - * @cliexend -?*/ -VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = { - .path = "snat deterministic close session out", - .short_help = "snat deterministic close session out " - "<out_addr>:<out_port> <ext_addr>:<ext_port>", - .function = snat_det_close_session_out_fn, -}; - -static clib_error_t * -snat_det_close_session_in_fn (vlib_main_t *vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - snat_main_t *sm = &snat_main; - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t in_addr, ext_addr; - u16 in_port, ext_port; - snat_det_map_t * dm; - snat_det_session_t * ses; - snat_det_out_key_t key; - clib_error_t *error = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "%U:%d %U:%d", - unformat_ip4_address, &in_addr, &in_port, - unformat_ip4_address, &ext_addr, &ext_port)) - ; - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - unformat_free (line_input); - - dm = snat_det_map_by_user (sm, &in_addr); - if (!dm) - vlib_cli_output (vm, "no match"); - else - { - key.ext_host_addr = ext_addr; - key.ext_host_port = ntohs (ext_port); - ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs(in_port), key); - if (!ses) - vlib_cli_output (vm, "no match"); - else - snat_det_ses_close(dm, ses); - } - -done: - unformat_free(line_input); - - return error; -} - -/*? - * @cliexpar - * @cliexstart{snat deterministic close_session_in} - * Close session using inside ip address and port - * and external ip address and port, use: - * vpp# snat deterministic close session in 3.3.3.3:3487 2.2.2.2:2387 - * @cliexend -?*/ -VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = { - .path = "snat deterministic close session in", - .short_help = "snat deterministic close session in " - "<in_addr>:<in_port> <ext_addr>:<ext_port>", - .function = snat_det_close_session_in_fn, -}; diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h deleted file mode 100644 index aa0f82fc9df..00000000000 --- a/src/plugins/snat/snat.h +++ /dev/null @@ -1,541 +0,0 @@ - -/* - * snat.h - simple nat definitions - * - * Copyright (c) 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. - */ -#ifndef __included_snat_h__ -#define __included_snat_h__ - -#include <vnet/vnet.h> -#include <vnet/ip/ip.h> -#include <vnet/ethernet/ethernet.h> -#include <vnet/ip/icmp46_packet.h> -#include <vnet/api_errno.h> -#include <vppinfra/bihash_8_8.h> -#include <vppinfra/bihash_16_8.h> -#include <vppinfra/dlist.h> -#include <vppinfra/error.h> -#include <vlibapi/api.h> - - -#define SNAT_UDP_TIMEOUT 300 -#define SNAT_UDP_TIMEOUT_MIN 120 -#define SNAT_TCP_TRANSITORY_TIMEOUT 240 -#define SNAT_TCP_ESTABLISHED_TIMEOUT 7440 -#define SNAT_TCP_INCOMING_SYN 6 -#define SNAT_ICMP_TIMEOUT 60 - -#define SNAT_FLAG_HAIRPINNING (1 << 0) - -/* Key */ -typedef struct { - union - { - struct - { - ip4_address_t addr; - u16 port; - u16 protocol:3, - fib_index:13; - }; - u64 as_u64; - }; -} snat_session_key_t; - -typedef struct { - union - { - struct - { - ip4_address_t l_addr; - ip4_address_t r_addr; - u32 fib_index; - u8 proto; - u8 rsvd[3]; - }; - u64 as_u64[2]; - }; -} snat_unk_proto_ses_key_t; - -typedef struct { - union - { - struct - { - ip4_address_t ext_host_addr; - u16 ext_host_port; - u16 out_port; - }; - u64 as_u64; - }; -} snat_det_out_key_t; - -typedef struct { - union - { - struct - { - ip4_address_t addr; - u32 fib_index; - }; - u64 as_u64; - }; -} snat_user_key_t; - -typedef struct { - union - { - struct - { - ip4_address_t addr; - u16 port; - u16 fib_index; - }; - u64 as_u64; - }; -} snat_worker_key_t; - - -#define foreach_snat_protocol \ - _(UDP, 0, udp, "udp") \ - _(TCP, 1, tcp, "tcp") \ - _(ICMP, 2, icmp, "icmp") - -typedef enum { -#define _(N, i, n, s) SNAT_PROTOCOL_##N = i, - foreach_snat_protocol -#undef _ -} snat_protocol_t; - - -#define foreach_snat_session_state \ - _(0, UNKNOWN, "unknown") \ - _(1, UDP_ACTIVE, "udp-active") \ - _(2, TCP_SYN_SENT, "tcp-syn-sent") \ - _(3, TCP_ESTABLISHED, "tcp-established") \ - _(4, TCP_FIN_WAIT, "tcp-fin-wait") \ - _(5, TCP_CLOSE_WAIT, "tcp-close-wait") \ - _(6, TCP_LAST_ACK, "tcp-last-ack") \ - _(7, ICMP_ACTIVE, "icmp-active") - -typedef enum { -#define _(v, N, s) SNAT_SESSION_##N = v, - foreach_snat_session_state -#undef _ -} snat_session_state_t; - - -#define SNAT_SESSION_FLAG_STATIC_MAPPING 1 -#define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2 - -typedef CLIB_PACKED(struct { - snat_session_key_t out2in; /* 0-15 */ - - snat_session_key_t in2out; /* 16-31 */ - - u32 flags; /* 32-35 */ - - /* per-user translations */ - u32 per_user_index; /* 36-39 */ - - u32 per_user_list_head_index; /* 40-43 */ - - /* Last heard timer */ - f64 last_heard; /* 44-51 */ - - u64 total_bytes; /* 52-59 */ - - u32 total_pkts; /* 60-63 */ - - /* Outside address */ - u32 outside_address_index; /* 64-67 */ - - /* External host address */ - ip4_address_t ext_host_addr; /* 68-71 */ - -}) snat_session_t; - - -typedef struct { - ip4_address_t addr; - u32 fib_index; - u32 sessions_per_user_list_head_index; - u32 nsessions; - u32 nstaticsessions; -} snat_user_t; - -typedef struct { - ip4_address_t addr; - u32 fib_index; -#define _(N, i, n, s) \ - u32 busy_##n##_ports; \ - uword * busy_##n##_port_bitmap; - foreach_snat_protocol -#undef _ -} snat_address_t; - -typedef struct { - u16 in_port; - snat_det_out_key_t out; - u8 state; - u32 expire; -} snat_det_session_t; - -typedef struct { - ip4_address_t in_addr; - u8 in_plen; - ip4_address_t out_addr; - u8 out_plen; - u32 sharing_ratio; - u16 ports_per_host; - u32 ses_num; - /* vector of sessions */ - snat_det_session_t * sessions; -} snat_det_map_t; - -typedef struct { - ip4_address_t local_addr; - ip4_address_t external_addr; - u16 local_port; - u16 external_port; - u8 addr_only; - u32 vrf_id; - u32 fib_index; - snat_protocol_t proto; -} snat_static_mapping_t; - -typedef struct { - u32 sw_if_index; - u8 is_inside; -} snat_interface_t; - -typedef struct { - ip4_address_t l_addr; - u16 l_port; - u16 e_port; - u32 sw_if_index; - u32 vrf_id; - snat_protocol_t proto; - int addr_only; - int is_add; -} snat_static_map_resolve_t; - -typedef struct { - /* User pool */ - snat_user_t * users; - - /* Session pool */ - snat_session_t * sessions; - - /* Pool of doubly-linked list elements */ - dlist_elt_t * list_pool; - - u32 snat_thread_index; -} snat_main_per_thread_data_t; - -struct snat_main_s; - -typedef u32 snat_icmp_match_function_t (struct snat_main_s *sm, - vlib_node_runtime_t *node, - u32 thread_index, - vlib_buffer_t *b0, - u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, - void *d, - void *e); - -typedef u32 (snat_get_worker_function_t) (ip4_header_t * ip, u32 rx_fib_index); - -typedef struct snat_main_s { - /* Main lookup tables */ - clib_bihash_8_8_t out2in; - clib_bihash_8_8_t in2out; - - /* Unknown protocol sessions lookup tables */ - clib_bihash_16_8_t out2in_unk_proto; - clib_bihash_16_8_t in2out_unk_proto; - - /* Find-a-user => src address lookup */ - clib_bihash_8_8_t user_hash; - - /* Non-translated packets worker lookup => src address + VRF */ - clib_bihash_8_8_t worker_by_in; - - /* Translated packets worker lookup => IP address + port number */ - clib_bihash_8_8_t worker_by_out; - - snat_icmp_match_function_t * icmp_match_in2out_cb; - snat_icmp_match_function_t * icmp_match_out2in_cb; - - u32 num_workers; - u32 first_worker_index; - u32 next_worker; - u32 * workers; - snat_get_worker_function_t * worker_in2out_cb; - snat_get_worker_function_t * worker_out2in_cb; - u16 port_per_thread; - u32 num_snat_thread; - - /* Per thread data */ - snat_main_per_thread_data_t * per_thread_data; - - /* Find a static mapping by local */ - clib_bihash_8_8_t static_mapping_by_local; - - /* Find a static mapping by external */ - clib_bihash_8_8_t static_mapping_by_external; - - /* Static mapping pool */ - snat_static_mapping_t * static_mappings; - - /* Interface pool */ - snat_interface_t * interfaces; - snat_interface_t * output_feature_interfaces; - - /* Vector of outside addresses */ - snat_address_t * addresses; - - /* sw_if_indices whose intfc addresses should be auto-added */ - u32 * auto_add_sw_if_indices; - - /* vector of interface address static mappings to resolve. */ - snat_static_map_resolve_t *to_resolve; - - /* Randomize port allocation order */ - u32 random_seed; - - /* Worker handoff index */ - u32 fq_in2out_index; - u32 fq_in2out_output_index; - u32 fq_out2in_index; - - /* in2out and out2in node index */ - u32 in2out_node_index; - u32 in2out_output_node_index; - u32 out2in_node_index; - - /* Deterministic NAT */ - snat_det_map_t * det_maps; - - /* Config parameters */ - u8 static_mapping_only; - u8 static_mapping_connection_tracking; - u8 deterministic; - u32 translation_buckets; - u32 translation_memory_size; - u32 user_buckets; - u32 user_memory_size; - u32 max_translations_per_user; - u32 outside_vrf_id; - u32 outside_fib_index; - u32 inside_vrf_id; - u32 inside_fib_index; - - /* tenant VRF aware address pool activation flag */ - u8 vrf_mode; - - /* values of various timeouts */ - u32 udp_timeout; - u32 tcp_established_timeout; - u32 tcp_transitory_timeout; - u32 icmp_timeout; - - /* API message ID base */ - u16 msg_id_base; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; - ip4_main_t * ip4_main; - ip_lookup_main_t * ip4_lookup_main; - api_main_t * api_main; -} snat_main_t; - -extern snat_main_t snat_main; -extern vlib_node_registration_t snat_in2out_node; -extern vlib_node_registration_t snat_in2out_output_node; -extern vlib_node_registration_t snat_out2in_node; -extern vlib_node_registration_t snat_in2out_fast_node; -extern vlib_node_registration_t snat_out2in_fast_node; -extern vlib_node_registration_t snat_in2out_worker_handoff_node; -extern vlib_node_registration_t snat_in2out_output_worker_handoff_node; -extern vlib_node_registration_t snat_out2in_worker_handoff_node; -extern vlib_node_registration_t snat_det_in2out_node; -extern vlib_node_registration_t snat_det_out2in_node; -extern vlib_node_registration_t snat_hairpin_dst_node; -extern vlib_node_registration_t snat_hairpin_src_node; - -void snat_free_outside_address_and_port (snat_main_t * sm, - snat_session_key_t * k, - u32 address_index); - -int snat_alloc_outside_address_and_port (snat_main_t * sm, - u32 fib_index, - u32 thread_index, - snat_session_key_t * k, - u32 * address_indexp); - -int snat_static_mapping_match (snat_main_t * sm, - snat_session_key_t match, - snat_session_key_t * mapping, - u8 by_external, - u8 *is_addr_only); - -void snat_add_del_addr_to_fib (ip4_address_t * addr, - u8 p_len, - u32 sw_if_index, - int is_add); - -format_function_t format_snat_user; - -typedef struct { - u32 cached_sw_if_index; - u32 cached_ip4_address; -} snat_runtime_t; - -/** \brief Check if SNAT session is created from static mapping. - @param s SNAT session - @return 1 if SNAT session is created from static mapping otherwise 0 -*/ -#define snat_is_session_static(s) s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING - -/** \brief Check if SNAT session for unknown protocol. - @param s SNAT session - @return 1 if SNAT session for unknown protocol otherwise 0 -*/ -#define snat_is_unk_proto_session(s) s->flags & SNAT_SESSION_FLAG_UNKNOWN_PROTO - -/* - * Why is this here? Because we don't need to touch this layer to - * simply reply to an icmp. We need to change id to a unique - * value to NAT an echo request/reply. - */ - -typedef struct { - u16 identifier; - u16 sequence; -} icmp_echo_header_t; - -always_inline u32 -ip_proto_to_snat_proto (u8 ip_proto) -{ - u32 snat_proto = ~0; - - snat_proto = (ip_proto == IP_PROTOCOL_UDP) ? SNAT_PROTOCOL_UDP : snat_proto; - snat_proto = (ip_proto == IP_PROTOCOL_TCP) ? SNAT_PROTOCOL_TCP : snat_proto; - snat_proto = (ip_proto == IP_PROTOCOL_ICMP) ? SNAT_PROTOCOL_ICMP : snat_proto; - snat_proto = (ip_proto == IP_PROTOCOL_ICMP6) ? SNAT_PROTOCOL_ICMP : snat_proto; - - return snat_proto; -} - -always_inline u8 -snat_proto_to_ip_proto (snat_protocol_t snat_proto) -{ - u8 ip_proto = ~0; - - ip_proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : ip_proto; - ip_proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : ip_proto; - ip_proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : ip_proto; - - return ip_proto; -} - -typedef struct { - u16 src_port, dst_port; -} tcp_udp_header_t; - -u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e); -u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e); -u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e); -u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e); -u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e); -u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, - snat_session_key_t *p_value, - u8 *p_dont_translate, void *d, void *e); -void increment_v4_address(ip4_address_t * a); -void snat_add_address(snat_main_t *sm, ip4_address_t *addr, u32 vrf_id); -int snat_del_address(snat_main_t *sm, ip4_address_t addr, u8 delete_sm); -int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, u32 vrf_id, int addr_only, - u32 sw_if_index, snat_protocol_t proto, int is_add); -clib_error_t * snat_api_init(vlib_main_t * vm, snat_main_t * sm); -int snat_set_workers (uword * bitmap); -int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del); -int snat_interface_add_del_output_feature(u32 sw_if_index, u8 is_inside, - int is_del); -int snat_add_interface_address(snat_main_t *sm, u32 sw_if_index, int is_del); -uword unformat_snat_protocol(unformat_input_t * input, va_list * args); -u8 * format_snat_protocol(u8 * s, va_list * args); - -static_always_inline u8 -icmp_is_error_message (icmp46_header_t * icmp) -{ - switch(icmp->type) - { - case ICMP4_destination_unreachable: - case ICMP4_time_exceeded: - case ICMP4_parameter_problem: - case ICMP4_source_quench: - case ICMP4_redirect: - case ICMP4_alternate_host_address: - return 1; - } - return 0; -} - -static_always_inline u8 -is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, - u32 ip4_addr) -{ - snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data; - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - if (first_int_addr) - rt->cached_ip4_address = first_int_addr->as_u32; - else - rt->cached_ip4_address = 0; - } - - if (PREDICT_FALSE(ip4_addr == rt->cached_ip4_address)) - return 1; - else - return 0; -} - -#endif /* __included_snat_h__ */ diff --git a/src/plugins/snat/snat_all_api_h.h b/src/plugins/snat/snat_all_api_h.h deleted file mode 100644 index 490177008e0..00000000000 --- a/src/plugins/snat/snat_all_api_h.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * snat_all_api_h.h - skeleton vpp engine plug-in api #include file - * - * Copyright (c) <current-year> <your-organization> - * 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 the generated file, see BUILT_SOURCES in Makefile.am */ -#include <snat/snat.api.h> diff --git a/src/plugins/snat/snat_api.c b/src/plugins/snat/snat_api.c deleted file mode 100644 index 227074f9cb4..00000000000 --- a/src/plugins/snat/snat_api.c +++ /dev/null @@ -1,1970 +0,0 @@ -/* - * 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. - */ -/** - * @file - * @brief SNAT plugin API implementation - */ - -#include <snat/snat.h> -#include <snat/snat_det.h> -#include <snat/nat64.h> -#include <vlibapi/api.h> -#include <vlibmemory/api.h> -#include <vlibsocket/api.h> -#include <snat/snat_msg_enum.h> -#include <vnet/fib/fib_table.h> - -/* define message structures */ -#define vl_typedefs -#include <snat/snat_all_api_h.h> -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include <snat/snat_all_api_h.h> -#undef vl_endianfun - -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) - -#define REPLY_MSG_ID_BASE sm->msg_id_base -#include <vlibapi/api_helper_macros.h> - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include <snat/snat_all_api_h.h> -#undef vl_api_version - -/* Macro to finish up custom dump fns */ -#define FINISH \ - vec_add1 (s, 0); \ - vl_print (handle, (char *)s); \ - vec_free (s); \ - return handle; - -static void - vl_api_snat_add_address_range_t_handler - (vl_api_snat_add_address_range_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_add_address_range_reply_t *rmp; - ip4_address_t this_addr; - u32 start_host_order, end_host_order; - u32 vrf_id; - int i, count; - int rv = 0; - u32 *tmp; - - if (mp->is_ip4 != 1) - { - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto send_reply; - } - - if (sm->static_mapping_only) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - tmp = (u32 *) mp->first_ip_address; - start_host_order = clib_host_to_net_u32 (tmp[0]); - tmp = (u32 *) mp->last_ip_address; - end_host_order = clib_host_to_net_u32 (tmp[0]); - - count = (end_host_order - start_host_order) + 1; - - vrf_id = clib_host_to_net_u32 (mp->vrf_id); - - if (count > 1024) - clib_warning ("%U - %U, %d addresses...", - format_ip4_address, mp->first_ip_address, - format_ip4_address, mp->last_ip_address, count); - - memcpy (&this_addr.as_u8, mp->first_ip_address, 4); - - for (i = 0; i < count; i++) - { - if (mp->is_add) - snat_add_address (sm, &this_addr, vrf_id); - else - rv = snat_del_address (sm, this_addr, 0); - - if (rv) - goto send_reply; - - increment_v4_address (&this_addr); - } - -send_reply: - REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY); -} - -static void *vl_api_snat_add_address_range_t_print - (vl_api_snat_add_address_range_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_add_address_range "); - s = format (s, "%U ", format_ip4_address, mp->first_ip_address); - if (memcmp (mp->first_ip_address, mp->last_ip_address, 4)) - { - s = format (s, " - %U ", format_ip4_address, mp->last_ip_address); - } - 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); - if (a->fib_index != ~0) - { - fib_table_t *fib = fib_table_get (a->fib_index, FIB_PROTOCOL_IP4); - rmp->vrf_id = ntohl (fib->ft_table_id); - } - else - rmp->vrf_id = ~0; - 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; - - /* *INDENT-OFF* */ - vec_foreach (a, sm->addresses) - send_snat_address_details (a, q, mp->context); - /* *INDENT-ON* */ -} - -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) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_interface_add_del_feature_reply_t *rmp; - u8 is_del = mp->is_add == 0; - u32 sw_if_index = ntohl (mp->sw_if_index); - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - rv = snat_interface_add_del (sw_if_index, mp->is_inside, is_del); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY); -} - -static void *vl_api_snat_interface_add_del_feature_t_print - (vl_api_snat_interface_add_del_feature_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_interface_add_del_feature "); - s = format (s, "sw_if_index %d %s %s", - clib_host_to_net_u32 (mp->sw_if_index), - mp->is_inside ? "in" : "out", mp->is_add ? "" : "del"); - - FINISH; -} - -static void - send_snat_interface_details - (snat_interface_t * i, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_interface_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_INTERFACE_DETAILS + sm->msg_id_base); - rmp->sw_if_index = ntohl (i->sw_if_index); - rmp->is_inside = i->is_inside; - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_interface_dump_t_handler (vl_api_snat_interface_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - snat_interface_t *i; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - pool_foreach (i, sm->interfaces, - ({ - send_snat_interface_details(i, q, mp->context); - })); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_interface_dump_t_print - (vl_api_snat_interface_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_interface_dump "); - - FINISH; -} - -static void - vl_api_snat_interface_add_del_output_feature_t_handler - (vl_api_snat_interface_add_del_output_feature_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_interface_add_del_output_feature_reply_t *rmp; - u8 is_del = mp->is_add == 0; - u32 sw_if_index = ntohl (mp->sw_if_index); - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - rv = snat_interface_add_del_output_feature (sw_if_index, mp->is_inside, - is_del); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_SNAT_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY); -} - -static void *vl_api_snat_interface_add_del_output_feature_t_print - (vl_api_snat_interface_add_del_output_feature_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_interface_add_del_output_feature "); - s = format (s, "sw_if_index %d %s %s", - clib_host_to_net_u32 (mp->sw_if_index), - mp->is_inside ? "in" : "out", mp->is_add ? "" : "del"); - - FINISH; -} - -static void -send_snat_interface_output_feature_details (snat_interface_t * i, - unix_shared_memory_queue_t * q, - u32 context) -{ - vl_api_snat_interface_output_feature_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_INTERFACE_OUTPUT_FEATURE_DETAILS + sm->msg_id_base); - rmp->sw_if_index = ntohl (i->sw_if_index); - rmp->context = context; - rmp->is_inside = i->is_inside; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void - vl_api_snat_interface_output_feature_dump_t_handler - (vl_api_snat_interface_output_feature_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - snat_interface_t *i; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - pool_foreach (i, sm->output_feature_interfaces, - ({ - send_snat_interface_output_feature_details(i, q, mp->context); - })); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_interface_output_feature_dump_t_print - (vl_api_snat_interface_output_feature_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_interface_output_feature_dump "); - - FINISH; -} - -static void - vl_api_snat_add_static_mapping_t_handler - (vl_api_snat_add_static_mapping_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_add_static_mapping_reply_t *rmp; - ip4_address_t local_addr, external_addr; - u16 local_port = 0, external_port = 0; - u32 vrf_id, external_sw_if_index; - int rv = 0; - snat_protocol_t proto; - - if (mp->is_ip4 != 1) - { - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto send_reply; - } - - memcpy (&local_addr.as_u8, mp->local_ip_address, 4); - memcpy (&external_addr.as_u8, mp->external_ip_address, 4); - if (mp->addr_only == 0) - { - local_port = clib_net_to_host_u16 (mp->local_port); - external_port = clib_net_to_host_u16 (mp->external_port); - } - vrf_id = clib_net_to_host_u32 (mp->vrf_id); - external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index); - proto = ip_proto_to_snat_proto (mp->protocol); - - rv = snat_add_static_mapping (local_addr, external_addr, local_port, - external_port, vrf_id, mp->addr_only, - external_sw_if_index, proto, mp->is_add); - -send_reply: - REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY); -} - -static void *vl_api_snat_add_static_mapping_t_print - (vl_api_snat_add_static_mapping_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_add_static_mapping "); - s = format (s, "protocol %d local_addr %U external_addr %U ", - mp->protocol, - format_ip4_address, mp->local_ip_address, - format_ip4_address, mp->external_ip_address); - - if (mp->addr_only == 0) - s = format (s, "local_port %d external_port %d ", - clib_net_to_host_u16 (mp->local_port), - clib_net_to_host_u16 (mp->external_port)); - - if (mp->vrf_id != ~0) - s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id)); - - if (mp->external_sw_if_index != ~0) - s = format (s, "external_sw_if_index %d", - clib_net_to_host_u32 (mp->external_sw_if_index)); - FINISH; -} - -static void - send_snat_static_mapping_details - (snat_static_mapping_t * m, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_static_mapping_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_STATIC_MAPPING_DETAILS + sm->msg_id_base); - rmp->is_ip4 = 1; - rmp->addr_only = m->addr_only; - clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4); - clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4); - rmp->local_port = htons (m->local_port); - rmp->external_port = htons (m->external_port); - rmp->external_sw_if_index = ~0; - rmp->vrf_id = htonl (m->vrf_id); - rmp->protocol = snat_proto_to_ip_proto (m->proto); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void - send_snat_static_map_resolve_details - (snat_static_map_resolve_t * m, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_static_mapping_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_STATIC_MAPPING_DETAILS + sm->msg_id_base); - rmp->is_ip4 = 1; - rmp->addr_only = m->addr_only; - clib_memcpy (rmp->local_ip_address, &(m->l_addr), 4); - rmp->local_port = htons (m->l_port); - rmp->external_port = htons (m->e_port); - rmp->external_sw_if_index = htonl (m->sw_if_index); - rmp->vrf_id = htonl (m->vrf_id); - rmp->protocol = snat_proto_to_ip_proto (m->proto); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void - vl_api_snat_static_mapping_dump_t_handler - (vl_api_snat_static_mapping_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - snat_static_mapping_t *m; - snat_static_map_resolve_t *rp; - int j; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - pool_foreach (m, sm->static_mappings, - ({ - send_snat_static_mapping_details (m, q, mp->context); - })); - /* *INDENT-ON* */ - - for (j = 0; j < vec_len (sm->to_resolve); j++) - { - rp = sm->to_resolve + j; - send_snat_static_map_resolve_details (rp, q, mp->context); - } -} - -static void *vl_api_snat_static_mapping_dump_t_print - (vl_api_snat_static_mapping_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_static_mapping_dump "); - - FINISH; -} - -static void -vl_api_snat_control_ping_t_handler (vl_api_snat_control_ping_t * mp) -{ - vl_api_snat_control_ping_reply_t *rmp; - snat_main_t *sm = &snat_main; - int rv = 0; - - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_SNAT_CONTROL_PING_REPLY, - ({ - rmp->vpe_pid = ntohl (getpid ()); - })); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_control_ping_t_print - (vl_api_snat_control_ping_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_control_ping "); - - FINISH; -} - -static void -vl_api_snat_show_config_t_handler (vl_api_snat_show_config_t * mp) -{ - vl_api_snat_show_config_reply_t *rmp; - snat_main_t *sm = &snat_main; - int rv = 0; - - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_SNAT_SHOW_CONFIG_REPLY, - ({ - rmp->translation_buckets = htonl (sm->translation_buckets); - rmp->translation_memory_size = htonl (sm->translation_memory_size); - rmp->user_buckets = htonl (sm->user_buckets); - rmp->user_memory_size = htonl (sm->user_memory_size); - rmp->max_translations_per_user = htonl (sm->max_translations_per_user); - rmp->outside_vrf_id = htonl (sm->outside_vrf_id); - rmp->inside_vrf_id = htonl (sm->inside_vrf_id); - rmp->static_mapping_only = sm->static_mapping_only; - rmp->static_mapping_connection_tracking = - sm->static_mapping_connection_tracking; - rmp->deterministic = sm->deterministic; - })); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_show_config_t_print - (vl_api_snat_show_config_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_show_config "); - - FINISH; -} - -static void -vl_api_snat_set_workers_t_handler (vl_api_snat_set_workers_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_set_workers_reply_t *rmp; - int rv = 0; - uword *bitmap = 0; - u64 mask = clib_net_to_host_u64 (mp->worker_mask); - - if (sm->num_workers < 2) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); - rv = snat_set_workers (bitmap); - clib_bitmap_free (bitmap); - -send_reply: - REPLY_MACRO (VL_API_SNAT_SET_WORKERS_REPLY); -} - -static void *vl_api_snat_set_workers_t_print - (vl_api_snat_set_workers_t * mp, void *handle) -{ - u8 *s; - uword *bitmap = 0; - u8 first = 1; - int i; - u64 mask = clib_net_to_host_u64 (mp->worker_mask); - - s = format (0, "SCRIPT: snat_set_workers "); - bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); - /* *INDENT-OFF* */ - clib_bitmap_foreach (i, bitmap, - ({ - if (first) - s = format (s, "%d", i); - else - s = format (s, ",%d", i); - first = 0; - })); - /* *INDENT-ON* */ - clib_bitmap_free (bitmap); - FINISH; -} - -static void - send_snat_worker_details - (u32 worker_index, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_worker_details_t *rmp; - snat_main_t *sm = &snat_main; - vlib_worker_thread_t *w = - vlib_worker_threads + worker_index + sm->first_worker_index; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_SNAT_WORKER_DETAILS + sm->msg_id_base); - rmp->context = context; - rmp->worker_index = htonl (worker_index); - rmp->lcore_id = htonl (w->lcore_id); - strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1); - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_worker_dump_t_handler (vl_api_snat_worker_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - u32 *worker_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - vec_foreach (worker_index, sm->workers) - send_snat_worker_details(*worker_index, q, mp->context); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_worker_dump_t_print - (vl_api_snat_worker_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_worker_dump "); - - FINISH; -} - -static void - vl_api_snat_add_del_interface_addr_t_handler - (vl_api_snat_add_del_interface_addr_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_add_del_interface_addr_reply_t *rmp; - u8 is_del = mp->is_add == 0; - u32 sw_if_index = ntohl (mp->sw_if_index); - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - rv = snat_add_interface_address (sm, sw_if_index, is_del); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_SNAT_ADD_DEL_INTERFACE_ADDR_REPLY); -} - -static void *vl_api_snat_add_del_interface_addr_t_print - (vl_api_snat_add_del_interface_addr_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_add_del_interface_addr "); - s = format (s, "sw_if_index %d %s", - clib_host_to_net_u32 (mp->sw_if_index), - mp->is_add ? "" : "del"); - - FINISH; -} - -static void - send_snat_interface_addr_details - (u32 sw_if_index, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_interface_addr_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_INTERFACE_ADDR_DETAILS + sm->msg_id_base); - rmp->sw_if_index = ntohl (sw_if_index); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void - vl_api_snat_interface_addr_dump_t_handler - (vl_api_snat_interface_addr_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - u32 *i; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - vec_foreach (i, sm->auto_add_sw_if_indices) - send_snat_interface_addr_details(*i, q, mp->context); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_interface_addr_dump_t_print - (vl_api_snat_interface_addr_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_interface_addr_dump "); - - FINISH; -} - -static void - vl_api_snat_ipfix_enable_disable_t_handler - (vl_api_snat_ipfix_enable_disable_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_ipfix_enable_disable_reply_t *rmp; - int rv = 0; - - rv = snat_ipfix_logging_enable_disable (mp->enable, - clib_host_to_net_u32 - (mp->domain_id), - clib_host_to_net_u16 - (mp->src_port)); - - REPLY_MACRO (VL_API_SNAT_IPFIX_ENABLE_DISABLE_REPLY); -} - -static void *vl_api_snat_ipfix_enable_disable_t_print - (vl_api_snat_ipfix_enable_disable_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_ipfix_enable_disable "); - if (mp->domain_id) - s = format (s, "domain %d ", clib_net_to_host_u32 (mp->domain_id)); - if (mp->src_port) - s = format (s, "src_port %d ", clib_net_to_host_u16 (mp->src_port)); - if (!mp->enable) - s = format (s, "disable "); - - FINISH; -} - -static void - send_snat_user_details - (snat_user_t * u, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_user_details_t *rmp; - snat_main_t *sm = &snat_main; - fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4); - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_SNAT_USER_DETAILS + sm->msg_id_base); - - rmp->vrf_id = ntohl (fib->ft_table_id); - - rmp->is_ip4 = 1; - clib_memcpy (rmp->ip_address, &(u->addr), 4); - rmp->nsessions = ntohl (u->nsessions); - rmp->nstaticsessions = ntohl (u->nstaticsessions); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_user_dump_t_handler (vl_api_snat_user_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - snat_main_per_thread_data_t *tsm; - snat_user_t *u; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - vec_foreach (tsm, sm->per_thread_data) - vec_foreach (u, tsm->users) - send_snat_user_details (u, q, mp->context); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_user_dump_t_print - (vl_api_snat_user_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_user_dump "); - - FINISH; -} - -static void - send_snat_user_session_details - (snat_session_t * s, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_user_session_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_USER_SESSION_DETAILS + sm->msg_id_base); - rmp->is_ip4 = 1; - clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4); - clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4); - rmp->is_static = s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING ? 1 : 0; - rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard); - rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes); - rmp->total_pkts = ntohl (s->total_pkts); - rmp->context = context; - if (snat_is_unk_proto_session (s)) - { - rmp->outside_port = 0; - rmp->inside_port = 0; - rmp->protocol = ntohs (s->in2out.port); - } - else - { - rmp->outside_port = s->out2in.port; - rmp->inside_port = s->in2out.port; - rmp->protocol = ntohs (snat_proto_to_ip_proto (s->in2out.protocol)); - } - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void - vl_api_snat_user_session_dump_t_handler - (vl_api_snat_user_session_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - snat_main_per_thread_data_t *tsm; - snat_session_t *s; - clib_bihash_kv_8_8_t key, value; - snat_user_key_t ukey; - snat_user_t *u; - u32 session_index, head_index, elt_index; - dlist_elt_t *head, *elt; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - if (!mp->is_ip4) - return; - - clib_memcpy (&ukey.addr, mp->ip_address, 4); - ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id)); - key.key = ukey.as_u64; - if (!clib_bihash_search_8_8 (&sm->worker_by_in, &key, &value)) - tsm = vec_elt_at_index (sm->per_thread_data, value.value); - else - tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - if (clib_bihash_search_8_8 (&sm->user_hash, &key, &value)) - return; - u = pool_elt_at_index (tsm->users, value.value); - if (!u->nsessions && !u->nstaticsessions) - return; - - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tsm->list_pool, head_index); - elt_index = head->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - session_index = elt->value; - while (session_index != ~0) - { - s = pool_elt_at_index (tsm->sessions, session_index); - - send_snat_user_session_details (s, q, mp->context); - - elt_index = elt->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - session_index = elt->value; - } -} - -static void *vl_api_snat_user_session_dump_t_print - (vl_api_snat_user_session_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_user_session_dump "); - s = format (s, "ip_address %U vrf_id %d\n", - format_ip4_address, mp->ip_address, - clib_net_to_host_u32 (mp->vrf_id)); - - FINISH; -} - -/****************************/ -/*** detrministic NAT/CGN ***/ -/****************************/ - -static void -vl_api_snat_add_det_map_t_handler (vl_api_snat_add_det_map_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_add_det_map_reply_t *rmp; - int rv = 0; - ip4_address_t in_addr, out_addr; - - clib_memcpy (&in_addr, mp->in_addr, 4); - clib_memcpy (&out_addr, mp->out_addr, 4); - rv = snat_det_add_map (sm, &in_addr, mp->in_plen, &out_addr, - mp->out_plen, mp->is_add); - - REPLY_MACRO (VL_API_SNAT_ADD_DET_MAP_REPLY); -} - -static void *vl_api_snat_add_det_map_t_print - (vl_api_snat_add_det_map_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_add_det_map "); - s = format (s, "inside address %U/%d outside address %U/%d\n", - format_ip4_address, mp->in_addr, mp->in_plen, - format_ip4_address, mp->out_addr, mp->out_plen); - - FINISH; -} - -static void -vl_api_snat_det_forward_t_handler (vl_api_snat_det_forward_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_det_forward_reply_t *rmp; - int rv = 0; - u16 lo_port = 0, hi_port = 0; - snat_det_map_t *dm; - ip4_address_t in_addr, out_addr; - - out_addr.as_u32 = 0; - clib_memcpy (&in_addr, mp->in_addr, 4); - dm = snat_det_map_by_user (sm, &in_addr); - if (!dm) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto send_reply; - } - - snat_det_forward (dm, &in_addr, &out_addr, &lo_port); - hi_port = lo_port + dm->ports_per_host - 1; - -send_reply: - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_SNAT_DET_FORWARD_REPLY, - ({ - rmp->out_port_lo = ntohs (lo_port); - rmp->out_port_hi = ntohs (hi_port); - rmp->is_ip4 = 1; - memset (rmp->out_addr, 0, 16); - clib_memcpy (rmp->out_addr, &out_addr, 4); - })) - /* *INDENT-ON* */ -} - -static void *vl_api_snat_det_forward_t_print - (vl_api_snat_det_forward_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: smat_det_forward_t"); - s = format (s, "inside ip address %U\n", format_ip4_address, mp->in_addr); - - FINISH; -} - -static void -vl_api_snat_det_reverse_t_handler (vl_api_snat_det_reverse_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_det_reverse_reply_t *rmp; - int rv = 0; - ip4_address_t out_addr, in_addr; - snat_det_map_t *dm; - - in_addr.as_u32 = 0; - clib_memcpy (&out_addr, mp->out_addr, 4); - dm = snat_det_map_by_out (sm, &out_addr); - if (!dm) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto send_reply; - } - - snat_det_reverse (dm, &out_addr, htons (mp->out_port), &in_addr); - -send_reply: - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_SNAT_DET_REVERSE_REPLY, - ({ - rmp->is_ip4 = 1; - memset (rmp->in_addr, 0, 16); - clib_memcpy (rmp->in_addr, &in_addr, 4); - })) - /* *INDENT-ON* */ -} - -static void *vl_api_snat_det_reverse_t_print - (vl_api_snat_det_reverse_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: smat_det_reverse_t"); - s = format (s, "outside ip address %U outside port %d", - format_ip4_address, mp->out_addr, ntohs (mp->out_port)); - - FINISH; -} - -static void - sent_snat_det_map_details - (snat_det_map_t * m, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_det_map_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_DET_MAP_DETAILS + sm->msg_id_base); - rmp->is_ip4 = 1; - clib_memcpy (rmp->in_addr, &m->in_addr, 4); - rmp->in_plen = m->in_plen; - clib_memcpy (rmp->out_addr, &m->out_addr, 4); - rmp->out_plen = m->out_plen; - rmp->sharing_ratio = htonl (m->sharing_ratio); - rmp->ports_per_host = htons (m->ports_per_host); - rmp->ses_num = htonl (m->ses_num); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_det_map_dump_t_handler (vl_api_snat_det_map_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - snat_det_map_t *m; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - vec_foreach(m, sm->det_maps) - sent_snat_det_map_details(m, q, mp->context); - /* *INDENT-ON* */ -} - -static void *vl_api_snat_det_map_dump_t_print - (vl_api_snat_det_map_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_det_map_dump "); - - FINISH; -} - -static void -vl_api_snat_det_set_timeouts_t_handler (vl_api_snat_det_set_timeouts_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_det_set_timeouts_reply_t *rmp; - int rv = 0; - - sm->udp_timeout = ntohl (mp->udp); - sm->tcp_established_timeout = ntohl (mp->tcp_established); - sm->tcp_transitory_timeout = ntohl (mp->tcp_transitory); - sm->icmp_timeout = ntohl (mp->icmp); - - REPLY_MACRO (VL_API_SNAT_DET_SET_TIMEOUTS_REPLY); -} - -static void *vl_api_snat_det_set_timeouts_t_print - (vl_api_snat_det_set_timeouts_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_det_set_timeouts "); - s = format (s, "udp %d tcp_established %d tcp_transitory %d icmp %d\n", - ntohl (mp->udp), - ntohl (mp->tcp_established), - ntohl (mp->tcp_transitory), ntohl (mp->icmp)); - - FINISH; -} - -static void -vl_api_snat_det_get_timeouts_t_handler (vl_api_snat_det_get_timeouts_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_det_get_timeouts_reply_t *rmp; - int rv = 0; - - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_SNAT_DET_GET_TIMEOUTS_REPLY, - ({ - rmp->udp = htonl (sm->udp_timeout); - rmp->tcp_established = htonl (sm->tcp_established_timeout); - rmp->tcp_transitory = htonl (sm->tcp_transitory_timeout); - rmp->icmp = htonl (sm->icmp_timeout); - })) - /* *INDENT-ON* */ -} - -static void *vl_api_snat_det_get_timeouts_t_print - (vl_api_snat_det_get_timeouts_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_det_get_timeouts"); - - FINISH; -} - -static void - vl_api_snat_det_close_session_out_t_handler - (vl_api_snat_det_close_session_out_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_det_close_session_out_reply_t *rmp; - ip4_address_t out_addr, ext_addr, in_addr; - snat_det_out_key_t key; - snat_det_map_t *dm; - snat_det_session_t *ses; - int rv = 0; - - clib_memcpy (&out_addr, mp->out_addr, 4); - clib_memcpy (&ext_addr, mp->ext_addr, 4); - - dm = snat_det_map_by_out (sm, &out_addr); - if (!dm) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto send_reply; - } - snat_det_reverse (dm, &ext_addr, ntohs (mp->out_port), &in_addr); - key.ext_host_addr = ext_addr; - key.ext_host_port = mp->ext_port; - key.out_port = mp->out_port; - ses = snat_det_get_ses_by_out (dm, &in_addr, key.as_u64); - if (!ses) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto send_reply; - } - snat_det_ses_close (dm, ses); - -send_reply: - REPLY_MACRO (VL_API_SNAT_DET_CLOSE_SESSION_OUT_REPLY); -} - -static void *vl_api_snat_det_close_session_out_t_print - (vl_api_snat_det_close_session_out_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_det_close_session_out "); - s = format (s, "out_addr %U out_port %d " - "ext_addr %U ext_port %d\n", - format_ip4_address, mp->out_addr, ntohs (mp->out_port), - format_ip4_address, mp->ext_addr, ntohs (mp->ext_port)); - - FINISH; -} - -static void - vl_api_snat_det_close_session_in_t_handler - (vl_api_snat_det_close_session_in_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_snat_det_close_session_in_reply_t *rmp; - ip4_address_t in_addr, ext_addr; - snat_det_out_key_t key; - snat_det_map_t *dm; - snat_det_session_t *ses; - int rv = 0; - - clib_memcpy (&in_addr, mp->in_addr, 4); - clib_memcpy (&ext_addr, mp->ext_addr, 4); - - dm = snat_det_map_by_user (sm, &in_addr); - if (!dm) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto send_reply; - } - key.ext_host_addr = ext_addr; - key.ext_host_port = mp->ext_port; - ses = snat_det_find_ses_by_in (dm, &in_addr, mp->in_port, key); - if (!ses) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto send_reply; - } - snat_det_ses_close (dm, ses); - -send_reply: - REPLY_MACRO (VL_API_SNAT_DET_CLOSE_SESSION_OUT_REPLY); -} - -static void *vl_api_snat_det_close_session_in_t_print - (vl_api_snat_det_close_session_in_t * mp, void *handle) -{ - u8 *s; - s = format (0, "SCRIPT: snat_det_close_session_in "); - s = format (s, "in_addr %U in_port %d " - "ext_addr %U ext_port %d\n", - format_ip4_address, mp->in_addr, ntohs (mp->in_port), - format_ip4_address, mp->ext_addr, ntohs (mp->ext_port)); - - FINISH; -} - -static void - send_snat_det_session_details - (snat_det_session_t * s, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_snat_det_session_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_DET_SESSION_DETAILS + sm->msg_id_base); - rmp->is_ip4 = 1; - rmp->in_port = s->in_port; - clib_memcpy (rmp->ext_addr, &s->out.ext_host_addr, 4); - rmp->ext_port = s->out.ext_host_port; - rmp->out_port = s->out.out_port; - rmp->state = s->state; - rmp->expire = ntohl (s->expire); - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_snat_det_session_dump_t_handler (vl_api_snat_det_session_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - snat_main_t *sm = &snat_main; - ip4_address_t user_addr; - snat_det_map_t *dm; - snat_det_session_t *s, empty_ses; - u16 i; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - if (!mp->is_ip4) - return; - - memset (&empty_ses, 0, sizeof (empty_ses)); - clib_memcpy (&user_addr, mp->user_addr, 4); - dm = snat_det_map_by_user (sm, &user_addr); - if (!dm) - return; - - s = dm->sessions + snat_det_user_ses_offset (&user_addr, dm->in_plen); - for (i = 0; i < SNAT_DET_SES_PER_USER; i++) - { - if (s->out.as_u64) - send_snat_det_session_details (s, q, mp->context); - s++; - } -} - -static void *vl_api_snat_det_session_dump_t_print - (vl_api_snat_det_session_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_det_session_dump "); - s = format (s, "user_addr %U\n", format_ip4_address, mp->user_addr); - - FINISH; -} - -/*************/ -/*** NAT64 ***/ -/*************/ - -static void - vl_api_nat64_add_del_pool_addr_range_t_handler - (vl_api_nat64_add_del_pool_addr_range_t * mp) -{ - vl_api_nat64_add_del_pool_addr_range_reply_t *rmp; - snat_main_t *sm = &snat_main; - nat64_main_t *nm = &nat64_main; - int rv = 0; - ip4_address_t this_addr; - u32 start_host_order, end_host_order; - u32 vrf_id; - int i, count; - u32 *tmp; - - if (nm->is_disabled) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - tmp = (u32 *) mp->start_addr; - start_host_order = clib_host_to_net_u32 (tmp[0]); - tmp = (u32 *) mp->end_addr; - end_host_order = clib_host_to_net_u32 (tmp[0]); - - count = (end_host_order - start_host_order) + 1; - - vrf_id = clib_host_to_net_u32 (mp->vrf_id); - - memcpy (&this_addr.as_u8, mp->start_addr, 4); - - for (i = 0; i < count; i++) - { - if ((rv = nat64_add_del_pool_addr (&this_addr, vrf_id, mp->is_add))) - goto send_reply; - - increment_v4_address (&this_addr); - } - -send_reply: - REPLY_MACRO (VL_API_NAT64_ADD_DEL_POOL_ADDR_RANGE_REPLY); -} - -static void *vl_api_nat64_add_del_pool_addr_range_t_print - (vl_api_nat64_add_del_pool_addr_range_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_add_del_pool_addr_range "); - s = format (s, "%U - %U vrf_id %u %s\n", - format_ip4_address, mp->start_addr, - format_ip4_address, mp->end_addr, - ntohl (mp->vrf_id), mp->is_add ? "" : "del"); - - FINISH; -} - -typedef struct nat64_api_walk_ctx_t_ -{ - unix_shared_memory_queue_t *q; - u32 context; -} nat64_api_walk_ctx_t; - -static int -nat64_api_pool_walk (snat_address_t * a, void *arg) -{ - vl_api_nat64_pool_addr_details_t *rmp; - snat_main_t *sm = &snat_main; - nat64_api_walk_ctx_t *ctx = arg; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_NAT64_POOL_ADDR_DETAILS + sm->msg_id_base); - clib_memcpy (rmp->address, &(a->addr), 4); - if (a->fib_index != ~0) - { - fib_table_t *fib = fib_table_get (a->fib_index, FIB_PROTOCOL_IP6); - if (!fib) - return -1; - rmp->vrf_id = ntohl (fib->ft_table_id); - } - else - rmp->vrf_id = ~0; - rmp->context = ctx->context; - - vl_msg_api_send_shmem (ctx->q, (u8 *) & rmp); - - return 0; -} - -static void -vl_api_nat64_pool_addr_dump_t_handler (vl_api_nat64_pool_addr_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - nat64_api_walk_ctx_t ctx = { - .q = q, - .context = mp->context, - }; - - nat64_pool_addr_walk (nat64_api_pool_walk, &ctx); -} - -static void * -vl_api_nat64_pool_addr_dump_t_print (vl_api_nat64_pool_addr_dump_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_pool_addr_dump\n"); - - FINISH; -} - -static void -vl_api_nat64_add_del_interface_t_handler (vl_api_nat64_add_del_interface_t * - mp) -{ - snat_main_t *sm = &snat_main; - nat64_main_t *nm = &nat64_main; - vl_api_nat64_add_del_interface_reply_t *rmp; - int rv = 0; - - if (nm->is_disabled) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - VALIDATE_SW_IF_INDEX (mp); - - rv = - nat64_add_del_interface (ntohl (mp->sw_if_index), mp->is_inside, - mp->is_add); - - BAD_SW_IF_INDEX_LABEL; - -send_reply: - REPLY_MACRO (VL_API_NAT64_ADD_DEL_INTERFACE_REPLY); -} - -static void * -vl_api_nat64_add_del_interface_t_print (vl_api_nat64_add_del_interface_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_add_del_interface "); - s = format (s, "sw_if_index %d %s %s", - clib_host_to_net_u32 (mp->sw_if_index), - mp->is_inside ? "in" : "out", mp->is_add ? "" : "del"); - - FINISH; -} - -static int -nat64_api_interface_walk (snat_interface_t * i, void *arg) -{ - vl_api_nat64_interface_details_t *rmp; - snat_main_t *sm = &snat_main; - nat64_api_walk_ctx_t *ctx = arg; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_NAT64_INTERFACE_DETAILS + sm->msg_id_base); - rmp->sw_if_index = ntohl (i->sw_if_index); - rmp->is_inside = i->is_inside; - rmp->context = ctx->context; - - vl_msg_api_send_shmem (ctx->q, (u8 *) & rmp); - - return 0; -} - -static void -vl_api_nat64_interface_dump_t_handler (vl_api_nat64_interface_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - nat64_api_walk_ctx_t ctx = { - .q = q, - .context = mp->context, - }; - - nat64_interfaces_walk (nat64_api_interface_walk, &ctx); -} - -static void * -vl_api_nat64_interface_dump_t_print (vl_api_nat64_interface_dump_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_interface_dump "); - - FINISH; -} - -static void - vl_api_nat64_add_del_static_bib_t_handler - (vl_api_nat64_add_del_static_bib_t * mp) -{ - snat_main_t *sm = &snat_main; - nat64_main_t *nm = &nat64_main; - vl_api_nat64_add_del_static_bib_reply_t *rmp; - ip6_address_t in_addr; - ip4_address_t out_addr; - int rv = 0; - - if (nm->is_disabled) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - memcpy (&in_addr.as_u8, mp->i_addr, 16); - memcpy (&out_addr.as_u8, mp->o_addr, 4); - - rv = - nat64_add_del_static_bib_entry (&in_addr, &out_addr, - clib_net_to_host_u16 (mp->i_port), - clib_net_to_host_u16 (mp->o_port), - mp->proto, - clib_net_to_host_u32 (mp->vrf_id), - mp->is_add); - -send_reply: - REPLY_MACRO (VL_API_NAT64_ADD_DEL_STATIC_BIB_REPLY); -} - -static void *vl_api_nat64_add_del_static_bib_t_print - (vl_api_nat64_add_del_static_bib_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_add_del_static_bib "); - s = format (s, "protocol %d i_addr %U o_addr %U ", - mp->proto, - format_ip6_address, mp->i_addr, format_ip4_address, mp->o_addr); - - if (mp->vrf_id != ~0) - s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id)); - - FINISH; -} - -static int -nat64_api_bib_walk (nat64_db_bib_entry_t * bibe, void *arg) -{ - vl_api_nat64_bib_details_t *rmp; - snat_main_t *sm = &snat_main; - nat64_api_walk_ctx_t *ctx = arg; - fib_table_t *fib; - - fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6); - if (!fib) - return -1; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_NAT64_BIB_DETAILS + sm->msg_id_base); - rmp->context = ctx->context; - clib_memcpy (rmp->i_addr, &(bibe->in_addr), 16); - clib_memcpy (rmp->o_addr, &(bibe->out_addr), 4); - rmp->i_port = bibe->in_port; - rmp->o_port = bibe->out_port; - rmp->vrf_id = ntohl (fib->ft_table_id); - rmp->proto = bibe->proto; - rmp->is_static = bibe->is_static; - rmp->ses_num = ntohl (bibe->ses_num); - - vl_msg_api_send_shmem (ctx->q, (u8 *) & rmp); - - return 0; -} - -static void -vl_api_nat64_bib_dump_t_handler (vl_api_nat64_bib_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - nat64_api_walk_ctx_t ctx = { - .q = q, - .context = mp->context, - }; - - nat64_db_bib_walk (&nm->db, mp->proto, nat64_api_bib_walk, &ctx); -} - -static void * -vl_api_nat64_bib_dump_t_print (vl_api_nat64_bib_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_bib_dump protocol %d", mp->proto); - - FINISH; -} - -static void -vl_api_nat64_set_timeouts_t_handler (vl_api_nat64_set_timeouts_t * mp) -{ - snat_main_t *sm = &snat_main; - nat64_main_t *nm = &nat64_main; - vl_api_nat64_set_timeouts_reply_t *rmp; - int rv = 0; - - if (nm->is_disabled) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - rv = nat64_set_icmp_timeout (ntohl (mp->icmp)); - if (rv) - goto send_reply; - rv = nat64_set_udp_timeout (ntohl (mp->udp)); - if (rv) - goto send_reply; - rv = - nat64_set_tcp_timeouts (ntohl (mp->tcp_trans), ntohl (mp->tcp_est), - ntohl (mp->tcp_incoming_syn)); - -send_reply: - REPLY_MACRO (VL_API_NAT64_SET_TIMEOUTS_REPLY); -} - -static void *vl_api_nat64_set_timeouts_t_print - (vl_api_nat64_set_timeouts_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_set_timeouts "); - s = - format (s, - "udp %d icmp %d, tcp_trans %d, tcp_est %d, tcp_incoming_syn %d\n", - ntohl (mp->udp), ntohl (mp->icmp), ntohl (mp->tcp_trans), - ntohl (mp->tcp_est), ntohl (mp->tcp_incoming_syn)); - - FINISH; -} - -static void -vl_api_nat64_get_timeouts_t_handler (vl_api_nat64_get_timeouts_t * mp) -{ - snat_main_t *sm = &snat_main; - nat64_main_t *nm = &nat64_main; - vl_api_nat64_get_timeouts_reply_t *rmp; - int rv = 0; - - if (nm->is_disabled) - return; - - /* *INDENT-OFF* */ - REPLY_MACRO2 (VL_API_NAT64_GET_TIMEOUTS_REPLY, - ({ - rmp->udp = htonl (nat64_get_udp_timeout()); - rmp->icmp = htonl (nat64_get_icmp_timeout()); - rmp->tcp_trans = htonl (nat64_get_tcp_trans_timeout()); - rmp->tcp_est = htonl (nat64_get_tcp_est_timeout()); - rmp->tcp_incoming_syn = htonl (nat64_get_tcp_incoming_syn_timeout()); - })) - /* *INDENT-ON* */ -} - -static void *vl_api_nat64_get_timeouts_t_print - (vl_api_nat64_get_timeouts_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_get_timeouts"); - - FINISH; -} - -static int -nat64_api_st_walk (nat64_db_st_entry_t * ste, void *arg) -{ - vl_api_nat64_st_details_t *rmp; - snat_main_t *sm = &snat_main; - nat64_api_walk_ctx_t *ctx = arg; - nat64_main_t *nm = &nat64_main; - nat64_db_bib_entry_t *bibe; - fib_table_t *fib; - - bibe = nat64_db_bib_entry_by_index (&nm->db, ste->proto, ste->bibe_index); - if (!bibe) - return -1; - - fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6); - if (!fib) - return -1; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_NAT64_ST_DETAILS + sm->msg_id_base); - rmp->context = ctx->context; - clib_memcpy (rmp->il_addr, &(bibe->in_addr), 16); - clib_memcpy (rmp->ol_addr, &(bibe->out_addr), 4); - rmp->il_port = bibe->in_port; - rmp->ol_port = bibe->out_port; - clib_memcpy (rmp->ir_addr, &(ste->in_r_addr), 16); - clib_memcpy (rmp->or_addr, &(ste->out_r_addr), 4); - rmp->il_port = ste->r_port; - rmp->vrf_id = ntohl (fib->ft_table_id); - rmp->proto = ste->proto; - - vl_msg_api_send_shmem (ctx->q, (u8 *) & rmp); - - return 0; -} - -static void -vl_api_nat64_st_dump_t_handler (vl_api_nat64_st_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - nat64_api_walk_ctx_t ctx = { - .q = q, - .context = mp->context, - }; - - nat64_db_st_walk (&nm->db, mp->proto, nat64_api_st_walk, &ctx); -} - -static void * -vl_api_nat64_st_dump_t_print (vl_api_nat64_st_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: snat_st_dump protocol %d", mp->proto); - - FINISH; -} - -static void -vl_api_nat64_add_del_prefix_t_handler (vl_api_nat64_add_del_prefix_t * mp) -{ - vl_api_nat64_add_del_prefix_reply_t *rmp; - snat_main_t *sm = &snat_main; - nat64_main_t *nm = &nat64_main; - ip6_address_t prefix; - int rv = 0; - - if (nm->is_disabled) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - - memcpy (&prefix.as_u8, mp->prefix, 16); - - rv = - nat64_add_del_prefix (&prefix, mp->prefix_len, - clib_net_to_host_u32 (mp->vrf_id), mp->is_add); -send_reply: - REPLY_MACRO (VL_API_NAT64_ADD_DEL_PREFIX_REPLY); -} - -static void * -vl_api_nat64_add_del_prefix_t_print (vl_api_nat64_add_del_prefix_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_add_del_prefix %U/%u vrf_id %u %s\n", - format_ip6_address, mp->prefix, mp->prefix_len, - ntohl (mp->vrf_id), mp->is_add ? "" : "del"); - - FINISH; -} - -static int -nat64_api_prefix_walk (nat64_prefix_t * p, void *arg) -{ - vl_api_nat64_prefix_details_t *rmp; - snat_main_t *sm = &snat_main; - nat64_api_walk_ctx_t *ctx = arg; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_NAT64_PREFIX_DETAILS + sm->msg_id_base); - clib_memcpy (rmp->prefix, &(p->prefix), 16); - rmp->prefix_len = p->plen; - rmp->vrf_id = ntohl (p->vrf_id); - rmp->context = ctx->context; - - vl_msg_api_send_shmem (ctx->q, (u8 *) & rmp); - - return 0; -} - -static void -vl_api_nat64_prefix_dump_t_handler (vl_api_nat64_prefix_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - nat64_main_t *nm = &nat64_main; - - if (nm->is_disabled) - return; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - nat64_api_walk_ctx_t ctx = { - .q = q, - .context = mp->context, - }; - - nat64_prefix_walk (nat64_api_prefix_walk, &ctx); -} - -static void * -vl_api_nat64_prefix_dump_t_print (vl_api_nat64_prefix_dump_t * mp, - void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: nat64_prefix_dump\n"); - - FINISH; -} - -/* List of message types that this plugin understands */ -#define foreach_snat_plugin_api_msg \ -_(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \ -_(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_ADDRESS_DUMP, snat_address_dump) \ -_(SNAT_INTERFACE_DUMP, snat_interface_dump) \ -_(SNAT_SET_WORKERS, snat_set_workers) \ -_(SNAT_WORKER_DUMP, snat_worker_dump) \ -_(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr) \ -_(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump) \ -_(SNAT_IPFIX_ENABLE_DISABLE, snat_ipfix_enable_disable) \ -_(SNAT_USER_DUMP, snat_user_dump) \ -_(SNAT_USER_SESSION_DUMP, snat_user_session_dump) \ -_(SNAT_INTERFACE_ADD_DEL_OUTPUT_FEATURE, \ - snat_interface_add_del_output_feature) \ -_(SNAT_INTERFACE_OUTPUT_FEATURE_DUMP, \ - snat_interface_output_feature_dump) \ -_(SNAT_ADD_DET_MAP, snat_add_det_map) \ -_(SNAT_DET_FORWARD, snat_det_forward) \ -_(SNAT_DET_REVERSE, snat_det_reverse) \ -_(SNAT_DET_MAP_DUMP, snat_det_map_dump) \ -_(SNAT_DET_SET_TIMEOUTS, snat_det_set_timeouts) \ -_(SNAT_DET_GET_TIMEOUTS, snat_det_get_timeouts) \ -_(SNAT_DET_CLOSE_SESSION_OUT, snat_det_close_session_out) \ -_(SNAT_DET_CLOSE_SESSION_IN, snat_det_close_session_in) \ -_(SNAT_DET_SESSION_DUMP, snat_det_session_dump) \ -_(NAT64_ADD_DEL_POOL_ADDR_RANGE, nat64_add_del_pool_addr_range) \ -_(NAT64_POOL_ADDR_DUMP, nat64_pool_addr_dump) \ -_(NAT64_ADD_DEL_INTERFACE, nat64_add_del_interface) \ -_(NAT64_INTERFACE_DUMP, nat64_interface_dump) \ -_(NAT64_ADD_DEL_STATIC_BIB, nat64_add_del_static_bib) \ -_(NAT64_BIB_DUMP, nat64_bib_dump) \ -_(NAT64_SET_TIMEOUTS, nat64_set_timeouts) \ -_(NAT64_GET_TIMEOUTS, nat64_get_timeouts) \ -_(NAT64_ST_DUMP, nat64_st_dump) \ -_(NAT64_ADD_DEL_PREFIX, nat64_add_del_prefix) \ -_(NAT64_PREFIX_DUMP, nat64_prefix_dump) - -/* Set up the API message handling tables */ -static clib_error_t * -snat_plugin_api_hookup (vlib_main_t * vm) -{ - snat_main_t *sm __attribute__ ((unused)) = &snat_main; -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ - #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_snat_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include <snat/snat_all_api_h.h> -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (snat_main_t * sm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base); - foreach_vl_msg_name_crc_snat; -#undef _ -} - -static void -plugin_custom_dump_configure (snat_main_t * sm) -{ -#define _(n,f) sm->api_main->msg_print_handlers \ - [VL_API_##n + sm->msg_id_base] \ - = (void *) vl_api_##f##_t_print; - foreach_snat_plugin_api_msg; -#undef _ -} - -clib_error_t * -snat_api_init (vlib_main_t * vm, snat_main_t * sm) -{ - u8 *name; - clib_error_t *error = 0; - - name = format (0, "snat_%08x%c", api_version, 0); - - /* Ask for a correctly-sized block of API message decode slots */ - sm->msg_id_base = - vl_msg_api_get_msg_ids ((char *) name, VL_MSG_FIRST_AVAILABLE); - - error = snat_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (sm, sm->api_main); - - plugin_custom_dump_configure (sm); - - vec_free (name); - - return error; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/snat_det.c b/src/plugins/snat/snat_det.c deleted file mode 100644 index 2d6fce85c0a..00000000000 --- a/src/plugins/snat/snat_det.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * snat_det.c - deterministic NAT - * - * 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. - */ -/** - * @file - * @brief deterministic NAT - */ - -#include <snat/snat_det.h> - - -/** - * @brief Add/delete deterministic NAT mapping. - * - * Create bijective mapping of inside address to outside address and port range - * pairs, with the purpose of enabling deterministic NAT to reduce logging in - * CGN deployments. - * - * @param sm SNAT main. - * @param in_addr Inside network address. - * @param in_plen Inside network prefix length. - * @param out_addr Outside network address. - * @param out_plen Outside network prefix length. - * @param is_add If 0 delete, otherwise add. - */ -int -snat_det_add_map (snat_main_t * sm, ip4_address_t * in_addr, u8 in_plen, - ip4_address_t * out_addr, u8 out_plen, int is_add) -{ - snat_det_map_t *det_map; - static snat_det_session_t empty_snat_det_session = { 0 }; - snat_interface_t *i; - ip4_address_t in_cmp, out_cmp; - u8 found = 0; - - in_cmp.as_u32 = in_addr->as_u32 & ip4_main.fib_masks[in_plen]; - out_cmp.as_u32 = out_addr->as_u32 & ip4_main.fib_masks[out_plen]; - vec_foreach (det_map, sm->det_maps) - { - /* Checking for overlapping addresses to be added here */ - if (det_map->in_addr.as_u32 == in_cmp.as_u32 && - det_map->in_plen == in_plen && - det_map->out_addr.as_u32 == out_cmp.as_u32 && - det_map->out_plen == out_plen) - { - found = 1; - break; - } - } - - /* If found, don't add again */ - if (found && is_add) - return VNET_API_ERROR_VALUE_EXIST; - - /* If not found, don't delete */ - if (!found && !is_add) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - if (is_add) - { - pool_get (sm->det_maps, det_map); - memset (det_map, 0, sizeof (*det_map)); - det_map->in_addr.as_u32 = in_cmp.as_u32; - det_map->in_plen = in_plen; - det_map->out_addr.as_u32 = out_cmp.as_u32; - det_map->out_plen = out_plen; - det_map->sharing_ratio = (1 << (32 - in_plen)) / (1 << (32 - out_plen)); - det_map->ports_per_host = (65535 - 1023) / det_map->sharing_ratio; - - vec_validate_init_empty (det_map->sessions, - SNAT_DET_SES_PER_USER * (1 << (32 - in_plen)) - - 1, empty_snat_det_session); - } - else - { - vec_free (det_map->sessions); - vec_del1 (sm->det_maps, det_map - sm->det_maps); - } - - /* Add/del external address range to FIB */ - /* *INDENT-OFF* */ - pool_foreach (i, sm->interfaces, - ({ - if (i->is_inside) - continue; - - snat_add_del_addr_to_fib(out_addr, out_plen, i->sw_if_index, is_add); - break; - })); - /* *INDENT-ON* */ - return 0; -} - -/** - * @brief The 'snat-det-expire-walk' process's main loop. - * - * Check expire time for active sessions. - */ -static uword -snat_det_expire_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, - vlib_frame_t * f) -{ - snat_main_t *sm = &snat_main; - snat_det_map_t *dm; - snat_det_session_t *ses; - - while (sm->deterministic) - { - vlib_process_wait_for_event_or_clock (vm, 10.0); - vlib_process_get_events (vm, NULL); - u32 now = (u32) vlib_time_now (vm); - /* *INDENT-OFF* */ - pool_foreach (dm, sm->det_maps, - ({ - vec_foreach(ses, dm->sessions) - { - /* Delete if session expired */ - if (ses->in_port && (ses->expire < now)) - snat_det_ses_close (dm, ses); - } - })); - /* *INDENT-ON* */ - } - - return 0; -} - -static vlib_node_registration_t snat_det_expire_walk_node; - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (snat_det_expire_walk_node, static) = { - .function = snat_det_expire_walk_fn, - .type = VLIB_NODE_TYPE_PROCESS, - .name = - "snat-det-expire-walk", -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/snat_det.h b/src/plugins/snat/snat_det.h deleted file mode 100644 index f4fdb256637..00000000000 --- a/src/plugins/snat/snat_det.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * snat_det.h - deterministic nat definitions - * - * 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. - */ -/** - * @file - * @brief deterministic NAT definitions - */ - -#ifndef __included_snat_det_h__ -#define __included_snat_det_h__ - -#include <vnet/ip/ip.h> -#include <snat/snat.h> -#include <snat/snat_ipfix_logging.h> - - -#define SNAT_DET_SES_PER_USER 1000 - - -int snat_det_add_map (snat_main_t * sm, ip4_address_t * in_addr, u8 in_plen, - ip4_address_t * out_addr, u8 out_plen, int is_add); - -always_inline int -is_addr_in_net (ip4_address_t * addr, ip4_address_t * net, u8 plen) -{ - if (net->as_u32 == (addr->as_u32 & ip4_main.fib_masks[plen])) - return 1; - return 0; -} - -always_inline snat_det_map_t * -snat_det_map_by_user (snat_main_t * sm, ip4_address_t * user_addr) -{ - snat_det_map_t *dm; - - /* *INDENT-OFF* */ - pool_foreach (dm, sm->det_maps, - ({ - if (is_addr_in_net(user_addr, &dm->in_addr, dm->in_plen)) - return dm; - })); - /* *INDENT-ON* */ - return 0; -} - -always_inline snat_det_map_t * -snat_det_map_by_out (snat_main_t * sm, ip4_address_t * out_addr) -{ - snat_det_map_t *dm; - - /* *INDENT-OFF* */ - pool_foreach (dm, sm->det_maps, - ({ - if (is_addr_in_net(out_addr, &dm->out_addr, dm->out_plen)) - return dm; - })); - /* *INDENT-ON* */ - return 0; -} - -always_inline void -snat_det_forward (snat_det_map_t * dm, ip4_address_t * in_addr, - ip4_address_t * out_addr, u16 * lo_port) -{ - u32 in_offset, out_offset; - - in_offset = clib_net_to_host_u32 (in_addr->as_u32) - - clib_net_to_host_u32 (dm->in_addr.as_u32); - out_offset = in_offset / dm->sharing_ratio; - out_addr->as_u32 = - clib_host_to_net_u32 (clib_net_to_host_u32 (dm->out_addr.as_u32) + - out_offset); - *lo_port = 1024 + dm->ports_per_host * (in_offset % dm->sharing_ratio); -} - -always_inline void -snat_det_reverse (snat_det_map_t * dm, ip4_address_t * out_addr, u16 out_port, - ip4_address_t * in_addr) -{ - u32 in_offset1, in_offset2, out_offset; - - out_offset = clib_net_to_host_u32 (out_addr->as_u32) - - clib_net_to_host_u32 (dm->out_addr.as_u32); - in_offset1 = out_offset * dm->sharing_ratio; - in_offset2 = (out_port - 1024) / dm->ports_per_host; - in_addr->as_u32 = - clib_host_to_net_u32 (clib_net_to_host_u32 (dm->in_addr.as_u32) + - in_offset1 + in_offset2); -} - -always_inline u32 -snat_det_user_ses_offset (ip4_address_t * addr, u8 plen) -{ - return (clib_net_to_host_u32 (addr->as_u32) & pow2_mask (32 - plen)) * - SNAT_DET_SES_PER_USER; -} - -always_inline snat_det_session_t * -snat_det_get_ses_by_out (snat_det_map_t * dm, ip4_address_t * in_addr, - u64 out_key) -{ - u32 user_offset; - u16 i; - - user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen); - for (i = 0; i < SNAT_DET_SES_PER_USER; i++) - { - if (dm->sessions[i + user_offset].out.as_u64 == out_key) - return &dm->sessions[i + user_offset]; - } - - return 0; -} - -always_inline snat_det_session_t * -snat_det_find_ses_by_in (snat_det_map_t * dm, ip4_address_t * in_addr, - u16 in_port, snat_det_out_key_t out_key) -{ - snat_det_session_t *ses; - u32 user_offset; - u16 i; - - user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen); - for (i = 0; i < SNAT_DET_SES_PER_USER; i++) - { - ses = &dm->sessions[i + user_offset]; - if (ses->in_port == in_port && - ses->out.ext_host_addr.as_u32 == out_key.ext_host_addr.as_u32 && - ses->out.ext_host_port == out_key.ext_host_port) - return &dm->sessions[i + user_offset]; - } - - return 0; -} - -always_inline snat_det_session_t * -snat_det_ses_create (snat_det_map_t * dm, ip4_address_t * in_addr, - u16 in_port, snat_det_out_key_t * out) -{ - u32 user_offset; - u16 i; - - user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen); - - for (i = 0; i < SNAT_DET_SES_PER_USER; i++) - { - if (!dm->sessions[i + user_offset].in_port) - { - if (__sync_bool_compare_and_swap - (&dm->sessions[i + user_offset].in_port, 0, in_port)) - { - dm->sessions[i + user_offset].out.as_u64 = out->as_u64; - dm->sessions[i + user_offset].state = SNAT_SESSION_UNKNOWN; - dm->sessions[i + user_offset].expire = 0; - __sync_add_and_fetch (&dm->ses_num, 1); - return &dm->sessions[i + user_offset]; - } - } - } - - snat_ipfix_logging_max_entries_per_user (in_addr->as_u32); - return 0; -} - -always_inline void -snat_det_ses_close (snat_det_map_t * dm, snat_det_session_t * ses) -{ - if (__sync_bool_compare_and_swap (&ses->in_port, ses->in_port, 0)) - { - ses->out.as_u64 = 0; - __sync_add_and_fetch (&dm->ses_num, -1); - } -} - -#endif /* __included_snat_det_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/snat/snat_ipfix_logging.c b/src/plugins/snat/snat_ipfix_logging.c deleted file mode 100644 index c68dc540d15..00000000000 --- a/src/plugins/snat/snat_ipfix_logging.c +++ /dev/null @@ -1,835 +0,0 @@ -/* - * snat_ipfix_logging.c - NAT Events IPFIX logging - * - * Copyright (c) 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. - */ - -#include <vnet/flow/flow_report.h> -#include <vlibmemory/api.h> -#include <snat/snat.h> -#include <snat/snat_ipfix_logging.h> - -snat_ipfix_logging_main_t snat_ipfix_logging_main; - -#define NAT44_SESSION_CREATE_LEN 26 -#define NAT_ADDRESSES_EXHAUTED_LEN 13 -#define MAX_ENTRIES_PER_USER_LEN 17 - -#define NAT44_SESSION_CREATE_FIELD_COUNT 8 -#define NAT_ADDRESSES_EXHAUTED_FIELD_COUNT 3 -#define MAX_ENTRIES_PER_USER_FIELD_COUNT 4 - -typedef struct { - u8 nat_event; - u32 src_ip; - u32 nat_src_ip; - snat_protocol_t snat_proto; - u16 src_port; - u16 nat_src_port; - u32 vrf_id; -} snat_ipfix_logging_nat44_ses_args_t; - -typedef struct { - u32 pool_id; -} snat_ipfix_logging_addr_exhausted_args_t; - -typedef struct { - u32 src_ip; -} snat_ipfix_logging_max_entries_per_user_args_t; - -/** - * @brief Create an IPFIX template packet rewrite string - * - * @param frm flow report main - * @param fr flow report - * @param collector_address collector address - * @param src_address source address - * @param collector_port collector - * @param event NAT event ID - * @param quota_event NAT quota exceeded event ID - * - * @returns template packet - */ -static inline u8 * -snat_template_rewrite (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, - nat_event_t event, - quota_exceed_event_t quota_event) -{ - snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; - ip4_header_t *ip; - udp_header_t *udp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - ipfix_template_header_t *t; - ipfix_field_specifier_t *f; - ipfix_field_specifier_t *first_field; - u8 *rewrite = 0; - ip4_ipfix_template_packet_t *tp; - u32 field_count = 0; - flow_report_stream_t *stream; - - stream = &frm->streams[fr->stream_index]; - silm->stream_index = fr->stream_index; - - if (event == NAT_ADDRESSES_EXHAUTED) - { - field_count = NAT_ADDRESSES_EXHAUTED_FIELD_COUNT; - silm->addr_exhausted_template_id = fr->template_id; - } - else if (event == NAT44_SESSION_CREATE) - { - field_count = NAT44_SESSION_CREATE_FIELD_COUNT; - silm->nat44_session_template_id = fr->template_id; - } - else if (event == QUOTA_EXCEEDED) - { - if (quota_event == MAX_ENTRIES_PER_USER) - { - field_count = MAX_ENTRIES_PER_USER_FIELD_COUNT; - silm->max_entries_per_user_template_id = fr->template_id; - } - } - - /* allocate rewrite space */ - vec_validate_aligned (rewrite, - sizeof (ip4_ipfix_template_packet_t) - + field_count * sizeof (ipfix_field_specifier_t) - 1, - CLIB_CACHE_LINE_BYTES); - - tp = (ip4_ipfix_template_packet_t *) rewrite; - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - t = (ipfix_template_header_t *) (s + 1); - first_field = f = (ipfix_field_specifier_t *) (t + 1); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->src_address.as_u32 = src_address->as_u32; - ip->dst_address.as_u32 = collector_address->as_u32; - udp->src_port = clib_host_to_net_u16 (stream->src_port); - udp->dst_port = clib_host_to_net_u16 (collector_port); - udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip)); - - /* FIXUP: message header export_time */ - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - /* Add TLVs to the template */ - if (event == NAT_ADDRESSES_EXHAUTED) - { - f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8); - f++; - f->e_id_length = ipfix_e_id_length (0, natEvent, 1); - f++; - f->e_id_length = ipfix_e_id_length (0, natPoolId, 4); - f++; - } - else if (event == NAT44_SESSION_CREATE) - { - f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8); - f++; - f->e_id_length = ipfix_e_id_length (0, natEvent, 1); - f++; - f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4); - f++; - f->e_id_length = ipfix_e_id_length (0, postNATSourceIPv4Address, 4); - f++; - f->e_id_length = ipfix_e_id_length (0, protocolIdentifier, 1); - f++; - f->e_id_length = ipfix_e_id_length (0, sourceTransportPort, 2); - f++; - f->e_id_length = ipfix_e_id_length (0, postNAPTSourceTransportPort, 2); - f++; - f->e_id_length = ipfix_e_id_length (0, ingressVRFID, 4); - f++; - } - else if (event == QUOTA_EXCEEDED) - { - if (quota_event == MAX_ENTRIES_PER_USER) - { - f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, - 8); - f++; - f->e_id_length = ipfix_e_id_length (0, natEvent, 1); - f++; - f->e_id_length = ipfix_e_id_length (0, natQuotaExceededEvent, 4); - f++; - f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4); - f++; - } - } - - /* Back to the template packet... */ - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - - ASSERT (f - first_field); - /* Field count in this template */ - t->id_count = ipfix_id_count (fr->template_id, f - first_field); - - /* set length in octets */ - s->set_id_length = - ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s); - - /* message length in octets */ - h->version_length = version_length ((u8 *) f - (u8 *) h); - - ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip); - ip->checksum = ip4_header_checksum (ip); - - return rewrite; -} - -u8 * -snat_template_rewrite_addr_exhausted (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port) -{ - return snat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, NAT_ADDRESSES_EXHAUTED, 0); -} - -u8 * -snat_template_rewrite_nat44_session (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port) -{ - return snat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, NAT44_SESSION_CREATE, 0); -} - -u8 * -snat_template_rewrite_max_entries_per_usr (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port) -{ - return snat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, QUOTA_EXCEEDED, - MAX_ENTRIES_PER_USER); -} - -static inline void -snat_ipfix_header_create (flow_report_main_t * frm, - vlib_buffer_t * b0, - u32 * offset) -{ - snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; - flow_report_stream_t *stream; - ip4_ipfix_template_packet_t * tp; - ipfix_message_header_t * h = 0; - ipfix_set_header_t * s = 0; - ip4_header_t * ip; - udp_header_t * udp; - - stream = &frm->streams[silm->stream_index]; - - b0->current_data = 0; - b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + - sizeof (*s); - b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); - vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index; - tp = vlib_buffer_get_current (b0); - ip = (ip4_header_t *) &tp->ip4; - udp = (udp_header_t *) (ip+1); - h = (ipfix_message_header_t *)(udp+1); - s = (ipfix_set_header_t *)(h+1); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->flags_and_fragment_offset = 0; - ip->src_address.as_u32 = frm->src_address.as_u32; - ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; - udp->src_port = clib_host_to_net_u16 (stream->src_port); - udp->dst_port = clib_host_to_net_u16 (frm->collector_port); - udp->checksum = 0; - - h->export_time = clib_host_to_net_u32 ( - (u32) (((f64)frm->unix_time_0) + (vlib_time_now(frm->vlib_main) - - frm->vlib_time_0))); - h->sequence_number = clib_host_to_net_u32 (stream->sequence_number++); - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - *offset = (u32) (((u8 *)(s+1)) - (u8 *)tp); -} - -static inline void -snat_ipfix_send (flow_report_main_t * frm, - vlib_frame_t * f, - vlib_buffer_t * b0, - u16 template_id) -{ - ip4_ipfix_template_packet_t * tp; - ipfix_message_header_t * h = 0; - ipfix_set_header_t * s = 0; - ip4_header_t * ip; - udp_header_t * udp; - vlib_main_t * vm = frm->vlib_main; - - tp = vlib_buffer_get_current (b0); - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - - s->set_id_length = ipfix_set_id_length (template_id, - b0->current_length - - (sizeof (*ip) + sizeof (*udp) + - sizeof (*h))); - h->version_length = version_length (b0->current_length - - (sizeof (*ip) + sizeof (*udp))); - - ip->length = clib_host_to_net_u16 (b0->current_length); - ip->checksum = ip4_header_checksum (ip); - udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); - - if (frm->udp_checksum) - { - udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); - if (udp->checksum == 0) - udp->checksum = 0xffff; - } - - ASSERT (ip->checksum == ip4_header_checksum (ip)); - - vlib_put_frame_to_node (vm, ip4_lookup_node.index, f); -} - -static void -snat_ipfix_logging_nat44_ses (u8 nat_event, u32 src_ip, u32 nat_src_ip, - snat_protocol_t snat_proto, u16 src_port, - u16 nat_src_port, u32 vrf_id, int do_flush) -{ - snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; - flow_report_main_t *frm = &flow_report_main; - vlib_frame_t *f; - vlib_buffer_t *b0 = 0; - u32 bi0 = ~0; - u32 offset; - vlib_main_t * vm = frm->vlib_main; - u64 now; - vlib_buffer_free_list_t *fl; - u8 proto = ~0; - - if (!silm->enabled) - return; - - proto = snat_proto_to_ip_proto (snat_proto); - - now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); - now += silm->milisecond_time_0; - - b0 = silm->nat44_session_buffer; - - if (PREDICT_FALSE (b0 == 0)) - { - if (do_flush) - return; - - if (vlib_buffer_alloc (vm, &bi0, 1) != 1) - { - clib_warning ("can't allocate buffer for NAT IPFIX event"); - return; - } - - b0 = silm->nat44_session_buffer = - vlib_get_buffer (vm, bi0); - fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); - vlib_buffer_init_for_free_list (b0, fl); - VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - offset = 0; - } - else - { - bi0 = vlib_get_buffer_index (vm, b0); - offset = silm->nat44_session_next_record_offset; - } - - f = silm->nat44_session_frame; - if (PREDICT_FALSE (f == 0)) - { - u32 * to_next; - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); - silm->nat44_session_frame = f; - to_next = vlib_frame_vector_args (f); - to_next[0] = bi0; - f->n_vectors = 1; - } - - if (PREDICT_FALSE (offset == 0)) - snat_ipfix_header_create (frm, b0, &offset); - - if (PREDICT_TRUE (do_flush == 0)) - { - u64 time_stamp = clib_host_to_net_u64 (now); - clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp)); - offset += sizeof (time_stamp); - - clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event)); - offset += sizeof (nat_event); - - clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip)); - offset += sizeof (src_ip); - - clib_memcpy (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip)); - offset += sizeof (nat_src_ip); - - clib_memcpy (b0->data + offset, &proto, sizeof (proto)); - offset += sizeof (proto); - - clib_memcpy (b0->data + offset, &src_port, sizeof (src_port)); - offset += sizeof (src_port); - - clib_memcpy (b0->data + offset, &nat_src_port, sizeof (nat_src_port)); - offset += sizeof (nat_src_port); - - clib_memcpy (b0->data + offset, &vrf_id, sizeof(vrf_id)); - offset += sizeof (vrf_id); - - b0->current_length += NAT44_SESSION_CREATE_LEN; - } - - if (PREDICT_FALSE (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu)) - { - snat_ipfix_send (frm, f, b0, silm->nat44_session_template_id); - silm->nat44_session_frame = 0; - silm->nat44_session_buffer = 0; - offset = 0; - } - silm->nat44_session_next_record_offset = offset; - } - -static void -snat_ipfix_logging_addr_exhausted (u32 pool_id, int do_flush) -{ - snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; - flow_report_main_t *frm = &flow_report_main; - vlib_frame_t *f; - vlib_buffer_t *b0 = 0; - u32 bi0 = ~0; - u32 offset; - vlib_main_t * vm = frm->vlib_main; - u64 now; - vlib_buffer_free_list_t *fl; - u8 nat_event = NAT_ADDRESSES_EXHAUTED; - - if (!silm->enabled) - return; - - now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); - now += silm->milisecond_time_0; - - b0 = silm->addr_exhausted_buffer; - - if (PREDICT_FALSE (b0 == 0)) - { - if (do_flush) - return; - - if (vlib_buffer_alloc (vm, &bi0, 1) != 1) - { - clib_warning ("can't allocate buffer for NAT IPFIX event"); - return; - } - - b0 = silm->addr_exhausted_buffer = - vlib_get_buffer (vm, bi0); - fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); - vlib_buffer_init_for_free_list (b0, fl); - VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - offset = 0; - } - else - { - bi0 = vlib_get_buffer_index (vm, b0); - offset = silm->addr_exhausted_next_record_offset; - } - - f = silm->addr_exhausted_frame; - if (PREDICT_FALSE (f == 0)) - { - u32 * to_next; - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); - silm->addr_exhausted_frame = f; - to_next = vlib_frame_vector_args (f); - to_next[0] = bi0; - f->n_vectors = 1; - } - - if (PREDICT_FALSE (offset == 0)) - snat_ipfix_header_create (frm, b0, &offset); - - if (PREDICT_TRUE (do_flush == 0)) - { - u64 time_stamp = clib_host_to_net_u64 (now); - clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp)); - offset += sizeof (time_stamp); - - clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event)); - offset += sizeof (nat_event); - - clib_memcpy (b0->data + offset, &pool_id, sizeof(pool_id)); - offset += sizeof (pool_id); - - b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN; - } - - if (PREDICT_FALSE (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu)) - { - snat_ipfix_send (frm, f, b0, silm->addr_exhausted_template_id); - silm->addr_exhausted_frame = 0; - silm->addr_exhausted_buffer = 0; - offset = 0; - } - silm->addr_exhausted_next_record_offset = offset; -} - -static void -snat_ipfix_logging_max_entries_per_usr (u32 src_ip, int do_flush) -{ - snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; - flow_report_main_t *frm = &flow_report_main; - vlib_frame_t *f; - vlib_buffer_t *b0 = 0; - u32 bi0 = ~0; - u32 offset; - vlib_main_t * vm = frm->vlib_main; - u64 now; - vlib_buffer_free_list_t *fl; - u8 nat_event = QUOTA_EXCEEDED; - u32 quota_event = MAX_ENTRIES_PER_USER; - - if (!silm->enabled) - return; - - now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); - now += silm->milisecond_time_0; - - b0 = silm->max_entries_per_user_buffer; - - if (PREDICT_FALSE (b0 == 0)) - { - if (do_flush) - return; - - if (vlib_buffer_alloc (vm, &bi0, 1) != 1) - { - clib_warning ("can't allocate buffer for NAT IPFIX event"); - return; - } - - b0 = silm->max_entries_per_user_buffer = - vlib_get_buffer (vm, bi0); - fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); - vlib_buffer_init_for_free_list (b0, fl); - VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - offset = 0; - } - else - { - bi0 = vlib_get_buffer_index (vm, b0); - offset = silm->max_entries_per_user_next_record_offset; - } - - f = silm->max_entries_per_user_frame; - if (PREDICT_FALSE (f == 0)) - { - u32 * to_next; - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); - silm->max_entries_per_user_frame = f; - to_next = vlib_frame_vector_args (f); - to_next[0] = bi0; - f->n_vectors = 1; - } - - if (PREDICT_FALSE (offset == 0)) - snat_ipfix_header_create (frm, b0, &offset); - - if (PREDICT_TRUE (do_flush == 0)) - { - u64 time_stamp = clib_host_to_net_u64 (now); - clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp)); - offset += sizeof (time_stamp); - - clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event)); - offset += sizeof (nat_event); - - clib_memcpy (b0->data + offset, "a_event, sizeof(quota_event)); - offset += sizeof (quota_event); - - clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip)); - offset += sizeof (src_ip); - - b0->current_length += MAX_ENTRIES_PER_USER_LEN; - } - - if (PREDICT_FALSE (do_flush || (offset + MAX_ENTRIES_PER_USER_LEN) > frm->path_mtu)) - { - snat_ipfix_send (frm, f, b0, silm->max_entries_per_user_template_id); - silm->max_entries_per_user_frame = 0; - silm->max_entries_per_user_buffer = 0; - offset = 0; - } - silm->max_entries_per_user_next_record_offset = offset; -} - -static void -snat_ipfix_logging_nat44_ses_rpc_cb (snat_ipfix_logging_nat44_ses_args_t *a) -{ - snat_ipfix_logging_nat44_ses(a->nat_event, a->src_ip, a->nat_src_ip, - a->snat_proto, a->src_port, a->nat_src_port, - a->vrf_id, 0); -} - -/** - * @brief Generate NAT44 session create event - * - * @param src_ip source IPv4 address - * @param nat_src_ip transaltes source IPv4 address - * @param snat_proto SNAT transport protocol - * @param src_port source port - * @param nat_src_port translated source port - * @param vrf_id VRF ID - */ -void -snat_ipfix_logging_nat44_ses_create (u32 src_ip, - u32 nat_src_ip, - snat_protocol_t snat_proto, - u16 src_port, - u16 nat_src_port, - u32 vrf_id) -{ - snat_ipfix_logging_nat44_ses_args_t a; - - a.nat_event = NAT44_SESSION_CREATE; - a.src_ip = src_ip; - a.nat_src_ip = nat_src_ip; - a.snat_proto = snat_proto; - a.src_port = src_port; - a.nat_src_port = nat_src_port; - a.vrf_id = vrf_id; - - vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a, - sizeof (a)); -} - -/** - * @brief Generate NAT44 session delete event - * - * @param src_ip source IPv4 address - * @param nat_src_ip transaltes source IPv4 address - * @param snat_proto SNAT transport protocol - * @param src_port source port - * @param nat_src_port translated source port - * @param vrf_id VRF ID - */ -void -snat_ipfix_logging_nat44_ses_delete (u32 src_ip, - u32 nat_src_ip, - snat_protocol_t snat_proto, - u16 src_port, - u16 nat_src_port, - u32 vrf_id) -{ - snat_ipfix_logging_nat44_ses_args_t a; - - a.nat_event = NAT44_SESSION_DELETE; - a.src_ip = src_ip; - a.nat_src_ip = nat_src_ip; - a.snat_proto = snat_proto; - a.src_port = src_port; - a.nat_src_port = nat_src_port; - a.vrf_id = vrf_id; - - vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a, - sizeof (a)); -} - -vlib_frame_t * -snat_data_callback_nat44_session (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, - u32 * to_next, - u32 node_index) -{ - snat_ipfix_logging_nat44_ses(0, 0, 0, 0, 0, 0, 0, 1); - return f; -} - -static void -snat_ipfix_logging_addr_exhausted_rpc_cb - (snat_ipfix_logging_addr_exhausted_args_t * a) -{ - snat_ipfix_logging_addr_exhausted(a->pool_id, 0); -} - -/** - * @brief Generate NAT addresses exhausted event - * - * @param pool_id NAT pool ID - */ -void -snat_ipfix_logging_addresses_exhausted(u32 pool_id) -{ - //TODO: This event SHOULD be rate limited - snat_ipfix_logging_addr_exhausted_args_t a; - - a.pool_id = pool_id; - - vl_api_rpc_call_main_thread (snat_ipfix_logging_addr_exhausted_rpc_cb, - (u8 *) &a, sizeof (a)); -} - -vlib_frame_t * -snat_data_callback_addr_exhausted (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, - u32 * to_next, - u32 node_index) -{ - snat_ipfix_logging_addr_exhausted(0, 1); - return f; -} - -static void -snat_ipfix_logging_max_entries_per_usr_rpc_cb - (snat_ipfix_logging_max_entries_per_user_args_t * a) -{ - snat_ipfix_logging_max_entries_per_usr(a->src_ip, 0); -} - -/** - * @brief Generate maximum entries per user exceeded event - * - * @param src_ip source IPv4 address - */ -void -snat_ipfix_logging_max_entries_per_user(u32 src_ip) -{ - //TODO: This event SHOULD be rate limited - snat_ipfix_logging_max_entries_per_user_args_t a; - - a.src_ip = src_ip; - - vl_api_rpc_call_main_thread (snat_ipfix_logging_max_entries_per_usr_rpc_cb, - (u8 *) &a, sizeof (a)); -} - -vlib_frame_t * -snat_data_callback_max_entries_per_usr (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, - u32 * to_next, - u32 node_index) -{ - snat_ipfix_logging_max_entries_per_usr(0, 1); - return f; -} - -/** - * @brief Enable/disable SNAT IPFIX logging - * - * @param enable 1 if enable, 0 if disable - * @param domain_id observation domain ID - * @param src_port source port number - * - * @returns 0 if success - */ -int -snat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) -{ - snat_main_t * sm = &snat_main; - snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; - flow_report_main_t *frm = &flow_report_main; - vnet_flow_report_add_del_args_t a; - int rv; - u8 e = enable ? 1 : 0; - - if (silm->enabled == e) - return 0; - - silm->enabled = e; - - memset (&a, 0, sizeof (a)); - a.is_add = enable; - a.domain_id = domain_id ? domain_id : 1; - a.src_port = src_port ? src_port : UDP_DST_PORT_ipfix; - - if (sm->deterministic) - { - a.rewrite_callback = snat_template_rewrite_max_entries_per_usr; - a.flow_data_callback = snat_data_callback_max_entries_per_usr; - - rv = vnet_flow_report_add_del (frm, &a, NULL); - if (rv) - { - clib_warning ("vnet_flow_report_add_del returned %d", rv); - return -1; - } - } - else - { - a.rewrite_callback = snat_template_rewrite_nat44_session; - a.flow_data_callback = snat_data_callback_nat44_session; - - rv = vnet_flow_report_add_del (frm, &a, NULL); - if (rv) - { - clib_warning ("vnet_flow_report_add_del returned %d", rv); - return -1; - } - - a.rewrite_callback = snat_template_rewrite_addr_exhausted; - a.flow_data_callback = snat_data_callback_addr_exhausted; - - rv = vnet_flow_report_add_del (frm, &a, NULL); - if (rv) - { - clib_warning ("vnet_flow_report_add_del returned %d", rv); - return -1; - } - } - - return 0; -} - -/** - * @brief Initialize SNAT IPFIX logging - * - * @param vm vlib main - */ -void -snat_ipfix_logging_init (vlib_main_t * vm) -{ - snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; - - silm->enabled = 0; - - /* Set up time reference pair */ - silm->vlib_time_0 = vlib_time_now (vm); - silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6; -} diff --git a/src/plugins/snat/snat_ipfix_logging.h b/src/plugins/snat/snat_ipfix_logging.h deleted file mode 100644 index 45c1a7bf8e1..00000000000 --- a/src/plugins/snat/snat_ipfix_logging.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * snat_ipfix_logging.h - NAT Events IPFIX logging - * - * Copyright (c) 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. - */ -#ifndef __included_snat_ipfix_logging_h__ -#define __included_snat_ipfix_logging_h__ - -typedef enum { - NAT_ADDRESSES_EXHAUTED = 3, - NAT44_SESSION_CREATE = 4, - NAT44_SESSION_DELETE = 5, - NAT_PORTS_EXHAUSTED = 12, - QUOTA_EXCEEDED = 13, -} nat_event_t; - -typedef enum { - MAX_ENTRIES_PER_USER = 3, -} quota_exceed_event_t; - -typedef struct { - /** S-NAT IPFIX logging enabled */ - u8 enabled; - - /** ipfix buffers under construction */ - vlib_buffer_t *nat44_session_buffer; - vlib_buffer_t *addr_exhausted_buffer; - vlib_buffer_t *max_entries_per_user_buffer; - - /** frames containing ipfix buffers */ - vlib_frame_t *nat44_session_frame; - vlib_frame_t *addr_exhausted_frame; - vlib_frame_t *max_entries_per_user_frame; - - /** next record offset */ - u32 nat44_session_next_record_offset; - u32 addr_exhausted_next_record_offset; - u32 max_entries_per_user_next_record_offset; - - /** Time reference pair */ - u64 milisecond_time_0; - f64 vlib_time_0; - - /** template IDs */ - u16 nat44_session_template_id; - u16 addr_exhausted_template_id; - u16 max_entries_per_user_template_id; - - /** stream index */ - u32 stream_index; -} snat_ipfix_logging_main_t; - -extern snat_ipfix_logging_main_t snat_ipfix_logging_main; - -void snat_ipfix_logging_init (vlib_main_t * vm); -int snat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port); -void snat_ipfix_logging_nat44_ses_create (u32 src_ip, u32 nat_src_ip, - snat_protocol_t snat_proto, - u16 src_port, u16 nat_src_port, - u32 vrf_id); -void snat_ipfix_logging_nat44_ses_delete (u32 src_ip, u32 nat_src_ip, - snat_protocol_t snat_proto, - u16 src_port, u16 nat_src_port, - u32 vrf_id); -void snat_ipfix_logging_addresses_exhausted(u32 pool_id); -void snat_ipfix_logging_max_entries_per_user(u32 src_ip); - -#endif /* __included_snat_ipfix_logging_h__ */ diff --git a/src/plugins/snat/snat_msg_enum.h b/src/plugins/snat/snat_msg_enum.h deleted file mode 100644 index 2c76fd51158..00000000000 --- a/src/plugins/snat/snat_msg_enum.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * snat_msg_enum.h - skeleton vpp engine plug-in message enumeration - * - * Copyright (c) <current-year> <your-organization> - * 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. - */ -#ifndef included_snat_msg_enum_h -#define included_snat_msg_enum_h - -#include <vppinfra/byte_order.h> - -#define vl_msg_id(n,h) n, -typedef enum { -#include <snat/snat_all_api_h.h> - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - -#endif /* included_snat_msg_enum_h */ diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c deleted file mode 100644 index 905b8fac66c..00000000000 --- a/src/plugins/snat/snat_test.c +++ /dev/null @@ -1,1167 +0,0 @@ - -/* - * snat.c - skeleton vpp-api-test plug-in - * - * Copyright (c) <current-year> <your-organization> - * 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 <vat/vat.h> -#include <vlibapi/api.h> -#include <vlibmemory/api.h> -#include <vlibsocket/api.h> -#include <vppinfra/error.h> -#include <vnet/ip/ip.h> -#include <snat/snat.h> - -#define __plugin_msg_base snat_test_main.msg_id_base -#include <vlibapi/vat_helper_macros.h> - -uword unformat_sw_if_index (unformat_input_t * input, va_list * args); - -/* Declare message IDs */ -#include <snat/snat_msg_enum.h> - -/* define message structures */ -#define vl_typedefs -#include <snat/snat_all_api_h.h> -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include <snat/snat_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include <snat/snat_all_api_h.h> -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include <snat/snat_all_api_h.h> -#undef vl_api_version - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} snat_test_main_t; - -snat_test_main_t snat_test_main; - -#define foreach_standard_reply_retval_handler \ -_(snat_add_address_range_reply) \ -_(snat_interface_add_del_feature_reply) \ -_(snat_add_static_mapping_reply) \ -_(snat_set_workers_reply) \ -_(snat_add_del_interface_addr_reply) \ -_(snat_ipfix_enable_disable_reply) \ -_(snat_add_det_map_reply) \ -_(snat_det_set_timeouts_reply) \ -_(snat_det_close_session_out_reply) \ -_(snat_det_close_session_in_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = snat_test_main.vat_main; \ - i32 retval = ntohl(mp->retval); \ - if (vam->async_mode) { \ - vam->async_errors += (retval < 0); \ - } else { \ - vam->retval = retval; \ - vam->result_ready = 1; \ - } \ - } -foreach_standard_reply_retval_handler; -#undef _ - -/* - * Table of message reply handlers, must include boilerplate handlers - * we just generated - */ -#define foreach_vpe_api_reply_msg \ -_(SNAT_ADD_ADDRESS_RANGE_REPLY, snat_add_address_range_reply) \ -_(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY, \ - 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_ADDRESS_DETAILS, snat_address_details) \ -_(SNAT_INTERFACE_DETAILS, snat_interface_details) \ -_(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply) \ -_(SNAT_WORKER_DETAILS, snat_worker_details) \ -_(SNAT_ADD_DEL_INTERFACE_ADDR_REPLY, \ - snat_add_del_interface_addr_reply) \ -_(SNAT_INTERFACE_ADDR_DETAILS, snat_interface_addr_details) \ -_(SNAT_IPFIX_ENABLE_DISABLE_REPLY, \ - snat_ipfix_enable_disable_reply) \ -_(SNAT_USER_DETAILS, snat_user_details) \ -_(SNAT_USER_SESSION_DETAILS, snat_user_session_details) \ -_(SNAT_ADD_DET_MAP_REPLY, snat_add_det_map_reply) \ -_(SNAT_DET_FORWARD_REPLY, snat_det_forward_reply) \ -_(SNAT_DET_REVERSE_REPLY, snat_det_reverse_reply) \ -_(SNAT_DET_MAP_DETAILS, snat_det_map_details) \ -_(SNAT_DET_SET_TIMEOUTS_REPLY, snat_det_set_timeouts_reply) \ -_(SNAT_DET_GET_TIMEOUTS_REPLY, snat_det_get_timeouts_reply) \ -_(SNAT_DET_CLOSE_SESSION_OUT_REPLY, \ - snat_det_close_session_out_reply) \ -_(SNAT_DET_CLOSE_SESSION_IN_REPLY, \ - snat_det_close_session_in_reply) \ -_(SNAT_DET_SESSION_DETAILS, snat_det_session_details) - -static int api_snat_add_address_range (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - 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; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - 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); - end_host_order = clib_host_to_net_u32 (end_addr.as_u32); - - if (end_host_order < start_host_order) - { - errmsg ("end address less than start address\n"); - return -99; - } - - count = (end_host_order - start_host_order) + 1; - - if (count > 1024) - { - errmsg ("%U - %U, %d addresses...\n", - format_ip4_address, &start_addr, - format_ip4_address, &end_addr, - count); - } - - M(SNAT_ADD_ADDRESS_RANGE, mp); - - 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(mp); - W (ret); - return ret; -} - -static int api_snat_interface_add_del_feature (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_interface_add_del_feature_t * mp; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u8 is_inside = 1; - u8 is_add = 1; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "sw_if_index %d", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "out")) - is_inside = 0; - else if (unformat (i, "in")) - is_inside = 1; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - if (sw_if_index_set == 0) - { - errmsg ("interface / sw_if_index required\n"); - return -99; - } - - M(SNAT_INTERFACE_ADD_DEL_FEATURE, mp); - mp->sw_if_index = ntohl(sw_if_index); - mp->is_add = is_add; - mp->is_inside = is_inside; - - S(mp); - W (ret); - return ret; -} - -static int api_snat_add_static_mapping(vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_add_static_mapping_t * mp; - u8 external_addr_set = 0; - u8 local_addr_set = 0; - u8 is_add = 1; - u8 addr_only = 1; - ip4_address_t local_addr, external_addr; - u32 local_port = 0, external_port = 0, vrf_id = ~0; - u32 sw_if_index = ~0; - u8 sw_if_index_set = 0; - u32 proto = ~0; - u8 proto_set = 0; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr)) - local_addr_set = 1; - else if (unformat (i, "external_addr %U", unformat_ip4_address, - &external_addr)) - external_addr_set = 1; - else if (unformat (i, "local_port %u", &local_port)) - addr_only = 0; - else if (unformat (i, "external_port %u", &external_port)) - addr_only = 0; - else if (unformat (i, "external_if %U", unformat_sw_if_index, vam, - &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "external_sw_if_index %d", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "vrf %u", &vrf_id)) - ; - else if (unformat (i, "protocol %u", &proto)) - proto_set = 1; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - if (!addr_only && !proto_set) - { - errmsg ("protocol required\n"); - return -99; - } - - if (!local_addr_set) - { - errmsg ("local addr required\n"); - return -99; - } - if (!external_addr_set && !sw_if_index_set) - { - errmsg ("external addr or interface required\n"); - return -99; - } - - M(SNAT_ADD_STATIC_MAPPING, mp); - mp->is_add = is_add; - mp->is_ip4 = 1; - mp->addr_only = addr_only; - mp->local_port = ntohs ((u16) local_port); - mp->external_port = ntohs ((u16) external_port); - mp->external_sw_if_index = ntohl (sw_if_index); - mp->vrf_id = ntohl (vrf_id); - mp->protocol = (u8) proto; - memcpy (mp->local_ip_address, &local_addr, 4); - memcpy (mp->external_ip_address, &external_addr, 4); - - S(mp); - W (ret); - return ret; -} - -static void vl_api_snat_control_ping_reply_t_handler - (vl_api_snat_control_ping_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - if (vam->async_mode) - { - vam->async_errors += (retval < 0); - } - else - { - vam->retval = retval; - vam->result_ready = 1; - } -} - -static void vl_api_snat_static_mapping_details_t_handler - (vl_api_snat_static_mapping_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - if (mp->addr_only && mp->external_sw_if_index != ~0) - fformat (vam->ofp, "%15U%6s%15d%6s%11d%6d\n", - format_ip4_address, &mp->local_ip_address, "", - ntohl (mp->external_sw_if_index), "", - ntohl (mp->vrf_id), - mp->protocol); - else if (mp->addr_only && mp->external_sw_if_index == ~0) - fformat (vam->ofp, "%15U%6s%15U%6s%11d%6d\n", - format_ip4_address, &mp->local_ip_address, "", - format_ip4_address, &mp->external_ip_address, "", - ntohl (mp->vrf_id), - mp->protocol); - else if (!mp->addr_only && mp->external_sw_if_index != ~0) - fformat (vam->ofp, "%15U%6d%15d%6d%11d%6d\n", - format_ip4_address, &mp->local_ip_address, - ntohs (mp->local_port), - ntohl (mp->external_sw_if_index), - ntohs (mp->external_port), - ntohl (mp->vrf_id), - mp->protocol); - else - fformat (vam->ofp, "%15U%6d%15U%6d%11d%6d\n", - format_ip4_address, &mp->local_ip_address, - ntohs (mp->local_port), - format_ip4_address, &mp->external_ip_address, - ntohs (mp->external_port), - ntohl (mp->vrf_id), - mp->protocol); - -} - -static int api_snat_static_mapping_dump(vat_main_t * vam) -{ - vl_api_snat_static_mapping_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_static_mapping_dump"); - return -99; - } - - fformat (vam->ofp, "%21s%21s\n", "local", "external"); - fformat (vam->ofp, "%15s%6s%15s%6s%11s%6s\n", "address", "port", - "address/if_idx", "port", "vrf", "proto"); - - M(SNAT_STATIC_MAPPING_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -static void vl_api_snat_show_config_reply_t_handler - (vl_api_snat_show_config_reply_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - i32 retval = ntohl (mp->retval); - - if (retval >= 0) - { - fformat (vam->ofp, "translation hash buckets %d\n", - ntohl (mp->translation_buckets)); - fformat (vam->ofp, "translation hash memory %d\n", - ntohl (mp->translation_memory_size)); - fformat (vam->ofp, "user hash buckets %d\n", ntohl (mp->user_buckets)); - fformat (vam->ofp, "user hash memory %d\n", ntohl (mp->user_memory_size)); - fformat (vam->ofp, "max translations per user %d\n", - ntohl (mp->max_translations_per_user)); - fformat (vam->ofp, "outside VRF id %d\n", ntohl (mp->outside_vrf_id)); - fformat (vam->ofp, "inside VRF id %d\n", ntohl (mp->inside_vrf_id)); - if (mp->static_mapping_only) - { - fformat (vam->ofp, "static mapping only"); - if (mp->static_mapping_connection_tracking) - fformat (vam->ofp, " connection tracking"); - fformat (vam->ofp, "\n"); - } - } - vam->retval = retval; - vam->result_ready = 1; -} - -static int api_snat_show_config(vat_main_t * vam) -{ - vl_api_snat_show_config_t * mp; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_show_config"); - return -99; - } - - M(SNAT_SHOW_CONFIG, mp); - S(mp); - W (ret); - return ret; -} - -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) -{ - vl_api_snat_address_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_ADDRESS_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -static void vl_api_snat_interface_details_t_handler - (vl_api_snat_interface_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat (vam->ofp, "sw_if_index %d %s\n", ntohl (mp->sw_if_index), - mp->is_inside ? "in" : "out"); -} - -static int api_snat_interface_dump(vat_main_t * vam) -{ - vl_api_snat_interface_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_INTERFACE_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -static int api_snat_set_workers (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_set_workers_t * mp; - uword *bitmap; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", unformat_bitmap_list, &bitmap)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - M(SNAT_SET_WORKERS, mp); - mp->worker_mask = clib_host_to_net_u64 (bitmap[0]); - - S(mp); - W (ret); - return ret; -} - -static void vl_api_snat_worker_details_t_handler - (vl_api_snat_worker_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat (vam->ofp, "worker_index %d (%s at lcore %u)\n", - ntohl (mp->worker_index), mp->name, ntohl (mp->lcore_id)); -} - -static int api_snat_worker_dump(vat_main_t * vam) -{ - vl_api_snat_worker_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_WORKER_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -static int api_snat_add_del_interface_addr (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_add_del_interface_addr_t * mp; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u8 is_add = 1; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "sw_if_index %d", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - if (sw_if_index_set == 0) - { - errmsg ("interface / sw_if_index required\n"); - return -99; - } - - M(SNAT_ADD_DEL_INTERFACE_ADDR, mp); - mp->sw_if_index = ntohl(sw_if_index); - mp->is_add = is_add; - - S(mp); - W (ret); - return ret; -} - -static void vl_api_snat_interface_addr_details_t_handler - (vl_api_snat_interface_addr_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat (vam->ofp, "sw_if_index %d\n", ntohl (mp->sw_if_index)); -} - -static int api_snat_interface_addr_dump(vat_main_t * vam) -{ - vl_api_snat_interface_addr_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_INTERFACE_ADDR_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -static int api_snat_ipfix_enable_disable (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_ipfix_enable_disable_t * mp; - u32 domain_id = 0; - u32 src_port = 0; - u8 enable = 1; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "domain %d", &domain_id)) - ; - else if (unformat (i, "src_port %d", &src_port)) - ; - else if (unformat (i, "disable")) - enable = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - } - - M(SNAT_IPFIX_ENABLE_DISABLE, mp); - mp->domain_id = htonl(domain_id); - mp->src_port = htons((u16) src_port); - mp->enable = enable; - - S(mp); - W (ret); - return ret; -} - -static void vl_api_snat_user_session_details_t_handler - (vl_api_snat_user_session_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat(vam->ofp, "%s session %U:%d to %U:%d protocol id %d " - "total packets %d total bytes %d\n", - mp->is_static ? "static" : "dynamic", - format_ip4_address, mp->inside_ip_address, ntohl(mp->inside_port), - format_ip4_address, mp->outside_ip_address, ntohl(mp->outside_port), - ntohl(mp->protocol), ntohl(mp->total_pkts), ntohl(mp->total_bytes)); -} - -static int api_snat_user_session_dump(vat_main_t * vam) -{ - unformat_input_t* i = vam->input; - vl_api_snat_user_session_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - ip4_address_t addr; - u32 vrf_id = ~0; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - if (unformat (i, "ip_address %U vrf_id %d", - unformat_ip4_address, &addr, &vrf_id)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_USER_SESSION_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - memset(mp->ip_address, 0, 16); - clib_memcpy(mp->ip_address, &addr, 4); - mp->vrf_id = htonl(vrf_id); - mp->is_ip4 = 1; - S(mp_ping); - - W (ret); - return ret; -} - -static void vl_api_snat_user_details_t_handler - (vl_api_snat_user_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat(vam->ofp, "user with ip %U with vrf_id %d " - "with %d sessions and %d static sessions\n", - format_ip4_address, mp->ip_address, ntohl(mp->vrf_id), - ntohl(mp->nsessions), ntohl(mp->nstaticsessions)); -} - -static int api_snat_user_dump(vat_main_t * vam) -{ - vl_api_snat_user_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_address_dump"); - return -99; - } - - M(SNAT_USER_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -static int api_snat_add_det_map (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_add_det_map_t * mp; - ip4_address_t in_addr, out_addr; - u32 in_plen, out_plen; - u8 is_add = 1; - int ret; - - if (unformat (i, "in %U/%d out %U/%d", - unformat_ip4_address, &in_addr, &in_plen, - unformat_ip4_address, &out_addr, &out_plen)) - ; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_ADD_DET_MAP, mp); - clib_memcpy(mp->in_addr, &in_addr, 4); - mp->in_plen = in_plen; - clib_memcpy(mp->out_addr, &out_addr, 4); - mp->out_plen = out_plen; - mp->is_add = is_add; - - S(mp); - W (ret); - return ret; -} - -static void vl_api_snat_det_forward_reply_t_handler - (vl_api_snat_det_forward_reply_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - i32 retval = ntohl(mp->retval); - - if (retval >= 0) - { - fformat (vam->ofp, "outside address %U", format_ip4_address, &mp->out_addr); - fformat (vam->ofp, " outside port range start %d", ntohs(mp->out_port_lo)); - fformat (vam->ofp, " outside port range end %d\n", ntohs(mp->out_port_hi)); - } - - vam->retval = retval; - vam->result_ready = 1; -} - -static int api_snat_det_forward (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_det_forward_t * mp; - ip4_address_t in_addr; - int ret; - - if (unformat (i, "%U", unformat_ip4_address, &in_addr)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_DET_FORWARD, mp); - clib_memcpy(mp->in_addr, &in_addr, 4); - - S(mp); - W(ret); - return ret; -} - -static void vl_api_snat_det_reverse_reply_t_handler - (vl_api_snat_det_reverse_reply_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - i32 retval = ntohl(mp->retval); - - if (retval >= 0) - { - fformat (vam->ofp, "inside address %U\n", format_ip4_address, &mp->in_addr); - } - - vam->retval = retval; - vam->result_ready = 1; -} - -static int api_snat_det_reverse (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_det_reverse_t * mp; - ip4_address_t out_addr; - u16 out_port; - int ret; - - if (unformat (i, "%U %d", unformat_ip4_address, &out_addr, &out_port)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_DET_REVERSE, mp); - clib_memcpy(mp->out_addr, &out_addr, 4); - mp->out_port = htons(out_port); - - S(mp); - W(ret); - return ret; -} - -static void vl_api_snat_det_map_details_t_handler - (vl_api_snat_det_map_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat (vam->ofp, "Deterministic S-NAT mapping in %U/%d out %U/%d " - "ports per host %d sharing ratio %d " - "number of sessions %d", - format_ip4_address, mp->in_addr, mp->in_plen, - format_ip4_address, mp->out_addr, mp->out_plen, - ntohs(mp->ports_per_host), ntohl(mp->sharing_ratio), - ntohl(mp->ses_num)); -} - -static int api_snat_det_map_dump(vat_main_t * vam) -{ - vl_api_snat_det_map_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_det_map_dump"); - return -99; - } - - M(SNAT_DET_MAP_DUMP, mp); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -static int api_snat_det_set_timeouts (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_det_set_timeouts_t * mp; - u32 udp = SNAT_UDP_TIMEOUT; - u32 tcp_established = SNAT_TCP_ESTABLISHED_TIMEOUT; - u32 tcp_transitory = SNAT_TCP_TRANSITORY_TIMEOUT; - u32 icmp = SNAT_ICMP_TIMEOUT; - int ret; - - if (unformat (i, "udp %d", &udp)) - ; - else if (unformat (i, "tcp_established %d", &tcp_established)) - ; - else if (unformat (i, "tcp_transitory %d", &tcp_transitory)) - ; - else if (unformat (i, "icmp %d", &icmp)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_DET_SET_TIMEOUTS, mp); - mp->udp = htonl(udp); - mp->tcp_established = htonl(tcp_established); - mp->tcp_transitory = htonl(tcp_transitory); - mp->icmp = htonl(icmp); - - S(mp); - W (ret); - return ret; -} - -static void vl_api_snat_det_get_timeouts_reply_t_handler - (vl_api_snat_det_get_timeouts_reply_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - i32 retval = ntohl (mp->retval); - - if (retval >= 0) - { - fformat (vam->ofp, "udp timeout: %dsec\n", ntohl (mp->udp)); - fformat (vam->ofp, "tcp-established timeout: %dsec", - ntohl (mp->tcp_established)); - fformat (vam->ofp, "tcp-transitory timeout: %dsec", - ntohl (mp->tcp_transitory)); - fformat (vam->ofp, "icmp timeout: %dsec", ntohl (mp->icmp)); - } - vam->retval = retval; - vam->result_ready = 1; -} - -static int api_snat_det_get_timeouts(vat_main_t * vam) -{ - vl_api_snat_det_get_timeouts_t * mp; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_show_config"); - return -99; - } - - M(SNAT_DET_GET_TIMEOUTS, mp); - S(mp); - W (ret); - return ret; -} - -static int api_snat_det_close_session_out (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_det_close_session_out_t * mp; - ip4_address_t out_addr, ext_addr; - u16 out_port, ext_port; - int ret; - - if (unformat (i, "%U:%d %U:%d", - unformat_ip4_address, &out_addr, &out_port, - unformat_ip4_address, &ext_addr, &ext_port)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_DET_CLOSE_SESSION_OUT, mp); - clib_memcpy(mp->out_addr, &out_addr, 4); - mp->out_port = ntohs(out_port); - clib_memcpy(mp->ext_addr, &ext_addr, 4); - mp->ext_port = ntohs(ext_port); - - S(mp); - W (ret); - return ret; -} - -static int api_snat_det_close_session_in (vat_main_t * vam) -{ - unformat_input_t * i = vam->input; - vl_api_snat_det_close_session_in_t * mp; - ip4_address_t in_addr, ext_addr; - u16 in_port, ext_port; - int ret; - - if (unformat (i, "%U:%d %U:%d", - unformat_ip4_address, &in_addr, &in_port, - unformat_ip4_address, &ext_addr, &ext_port)) - ; - else - { - clib_warning("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_DET_CLOSE_SESSION_IN, mp); - clib_memcpy(mp->in_addr, &in_addr, 4); - mp->in_port = ntohs(in_port); - clib_memcpy(mp->ext_addr, &ext_addr, 4); - mp->ext_port = ntohs(ext_port); - - S(mp); - W (ret); - return ret; -} - -static void vl_api_snat_det_session_details_t_handler - (vl_api_snat_det_session_details_t *mp) -{ - snat_test_main_t * sm = &snat_test_main; - vat_main_t *vam = sm->vat_main; - - fformat(vam->ofp, "deterministic session, external host address %U, " - "external host port %d, outer port %d, inside port %d", - format_ip4_address, mp->ext_addr, mp->ext_port, - mp->out_port, mp->in_port); -} - -static int api_snat_det_session_dump(vat_main_t * vam) -{ - unformat_input_t* i = vam->input; - vl_api_snat_det_session_dump_t * mp; - vl_api_snat_control_ping_t *mp_ping; - ip4_address_t user_addr; - int ret; - - if (vam->json_output) - { - clib_warning ("JSON output not supported for snat_det_session_dump"); - return -99; - } - - if (unformat (i, "user_addr %U", unformat_ip4_address, &user_addr)) - ; - else - { - clib_warning ("unknown input '%U'", format_unformat_error, i); - return -99; - } - - M(SNAT_DET_SESSION_DUMP, mp); - clib_memcpy (&mp->user_addr, &user_addr, 4); - S(mp); - - /* Use a control ping for synchronization */ - M(SNAT_CONTROL_PING, mp_ping); - S(mp_ping); - - W (ret); - return ret; -} - -/* - * 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, "<start-addr> [- <end-addr] [del]") \ -_(snat_interface_add_del_feature, \ - "<intfc> | sw_if_index <id> [in] [out] [del]") \ -_(snat_add_static_mapping, "local_addr <ip> (external_addr <ip>" \ - " | external_if <intfc> | external_sw_if_ndex <id>) " \ - "[local_port <n>] [external_port <n>] [vrf <table-id>] [del] " \ - "protocol <n>") \ -_(snat_set_workers, "<wokrers_bitmap>") \ -_(snat_static_mapping_dump, "") \ -_(snat_show_config, "") \ -_(snat_address_dump, "") \ -_(snat_interface_dump, "") \ -_(snat_worker_dump, "") \ -_(snat_add_del_interface_addr, \ - "<intfc> | sw_if_index <id> [del]") \ -_(snat_interface_addr_dump, "") \ -_(snat_ipfix_enable_disable, "[domain <id>] [src_port <n>] " \ - "[disable]") \ -_(snat_user_dump, "") \ -_(snat_user_session_dump, "ip_address <ip> vrf_id <table-id>") \ -_(snat_add_det_map, "in <in_addr>/<in_plen> out " \ - "<out_addr>/<out_plen> [del]") \ -_(snat_det_forward, "<in_addr>") \ -_(snat_det_reverse, "<out_addr> <out_port>") \ -_(snat_det_map_dump, "") \ -_(snat_det_set_timeouts, "[udp <sec> | tcp_established <sec> | " \ - "tcp_transitory <sec> | icmp <sec>]") \ -_(snat_det_get_timeouts, "") \ -_(snat_det_close_session_out, "<out_addr>:<out_port> " \ - "<ext_addr>:<ext_port>") \ -_(snat_det_close_session_in, "<in_addr>:<in_port> " \ - "<out_addr>:<out_port>") \ -_(snat_det_session_dump, "ip_address <user_addr>") - -static void -snat_vat_api_hookup (vat_main_t *vam) -{ - snat_test_main_t * sm __attribute__((unused)) = &snat_test_main; - /* Hook up handlers for replies from the data plane plug-in */ -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ - #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_vpe_api_reply_msg; -#undef _ - - /* API messages we can send */ -#define _(n,h) \ - hash_set_mem (vam->function_by_name, #n, api_##n); - foreach_vpe_api_msg; -#undef _ - - /* Help strings */ -#define _(n,h) hash_set_mem (vam->help_by_name, #n, h); - foreach_vpe_api_msg; -#undef _ -} - -clib_error_t * vat_plugin_register (vat_main_t *vam) -{ - snat_test_main_t * sm = &snat_test_main; - u8 * name; - - sm->vat_main = vam; - - /* Ask the vpp engine for the first assigned message-id */ - name = format (0, "snat_%08x%c", api_version, 0); - sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - if (sm->msg_id_base != (u16) ~0) - snat_vat_api_hookup (vam); - - vec_free(name); - - return 0; -} |