X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fsnat%2Fsnat.h;h=61ed52f61e28a6e57f903b6e8920a2d64c22ca91;hb=refs%2Fchanges%2F99%2F7699%2F1;hp=32dc9f9e0a6ee094fcea22d2298866344ac6dda1;hpb=09d96f4a611fa989bfbbfb7e683d668dbe73ac1a;p=vpp.git diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h index 32dc9f9e0a6..61ed52f61e2 100644 --- a/src/plugins/snat/snat.h +++ b/src/plugins/snat/snat.h @@ -24,10 +24,21 @@ #include #include #include +#include #include #include #include + +#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 @@ -43,6 +54,34 @@ typedef struct { }; } 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 { @@ -81,7 +120,25 @@ typedef enum { } 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 */ @@ -105,11 +162,15 @@ typedef CLIB_PACKED(struct { /* 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; @@ -117,6 +178,7 @@ typedef struct { typedef struct { ip4_address_t addr; + u32 fib_index; #define _(N, i, n, s) \ u32 busy_##n##_ports; \ uword * busy_##n##_port_bitmap; @@ -124,6 +186,25 @@ typedef struct { #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; @@ -162,11 +243,29 @@ typedef struct { dlist_elt_t * list_pool; } snat_main_per_thread_data_t; -typedef struct { +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; @@ -176,10 +275,15 @@ typedef struct { /* 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; /* Per thread data */ snat_main_per_thread_data_t * per_thread_data; @@ -195,6 +299,7 @@ typedef struct { /* Interface pool */ snat_interface_t * interfaces; + snat_interface_t * output_feature_interfaces; /* Vector of outside addresses */ snat_address_t * addresses; @@ -210,11 +315,21 @@ typedef struct { /* 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; @@ -225,6 +340,15 @@ typedef struct { 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; @@ -233,30 +357,42 @@ typedef struct { vnet_main_t * vnet_main; ip4_main_t * ip4_main; ip_lookup_main_t * ip4_lookup_main; - ethernet_main_t * ethernet_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, 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 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; @@ -271,6 +407,12 @@ typedef struct { */ #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 @@ -282,14 +424,15 @@ typedef struct { u16 sequence; } icmp_echo_header_t; -always_inline snat_protocol_t +always_inline u32 ip_proto_to_snat_proto (u8 ip_proto) { - snat_protocol_t snat_proto = ~0; + 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; } @@ -306,4 +449,88 @@ snat_proto_to_ip_proto (snat_protocol_t snat_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__ */