X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fnat_inlines.h;h=d53e2453607613c94dc93bbcd5e8a969a19a3850;hb=5db2f4a4312112ab57043ce88f10edc4acc141ec;hp=e3a6f1942f75b7734109d29d5cc96095cdc0cadd;hpb=22bb417e91c7bdf639b24b5edd321028f56ea04a;p=vpp.git diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h index e3a6f1942f7..d53e2453607 100644 --- a/src/plugins/nat/nat_inlines.h +++ b/src/plugins/nat/nat_inlines.h @@ -21,49 +21,200 @@ #include #include -#include +//#include -always_inline u32 -ip_proto_to_snat_proto (u8 ip_proto) +always_inline u64 +calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto) { - u32 snat_proto = ~0; + ASSERT (fib_index <= (1 << 14) - 1); + ASSERT (proto <= (1 << 3) - 1); + return (u64) addr.as_u32 << 32 | (u64) port << 16 | fib_index << 3 | + (proto & 0x7); +} - 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; +always_inline void +split_nat_key (u64 key, ip4_address_t * addr, u16 * port, + u32 * fib_index, nat_protocol_t * proto) +{ + if (addr) + { + addr->as_u32 = key >> 32; + } + if (port) + { + *port = (key >> 16) & (u16) ~ 0; + } + if (fib_index) + { + *fib_index = key >> 3 & ((1 << 13) - 1); + } + if (proto) + { + *proto = key & 0x7; + } +} - return snat_proto; +always_inline void +init_nat_k (clib_bihash_kv_8_8_t * kv, ip4_address_t addr, u16 port, + u32 fib_index, nat_protocol_t proto) +{ + kv->key = calc_nat_key (addr, port, fib_index, proto); + kv->value = ~0ULL; } -always_inline u8 -snat_proto_to_ip_proto (snat_protocol_t snat_proto) +always_inline void +init_nat_kv (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port, + u32 fib_index, nat_protocol_t proto, u32 thread_index, + u32 session_index) { - u8 ip_proto = ~0; + init_nat_k (kv, addr, port, fib_index, proto); + kv->value = (u64) thread_index << 32 | session_index; +} - 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; +always_inline void +init_nat_i2o_k (clib_bihash_kv_8_8_t * kv, snat_session_t * s) +{ + return init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index, + s->nat_proto); +} - return ip_proto; +always_inline void +init_nat_i2o_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index, + u32 session_index) +{ + init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index, + s->nat_proto); + kv->value = (u64) thread_index << 32 | session_index; } -static_always_inline u8 -icmp_is_error_message (icmp46_header_t * icmp) +always_inline void +init_nat_o2i_k (clib_bihash_kv_8_8_t * kv, snat_session_t * s) +{ + return init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index, + s->nat_proto); +} + +always_inline void +init_nat_o2i_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index, + u32 session_index) +{ + init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index, + s->nat_proto); + kv->value = (u64) thread_index << 32 | session_index; +} + +always_inline u32 +nat_value_get_thread_index (clib_bihash_kv_8_8_t *value) { - switch (icmp->type) + return value->value >> 32; +} + +always_inline u32 +nat_value_get_session_index (clib_bihash_kv_8_8_t *value) +{ + return value->value & ~(u32) 0; +} + +static inline uword +nat_pre_node_fn_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, u32 def_next) +{ + u32 n_left_from, *from; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs; + u16 nexts[VLIB_FRAME_SIZE], *next = nexts; + vlib_get_buffers (vm, from, b, n_left_from); + + while (n_left_from >= 2) + { + u32 next0, next1; + u32 arc_next0, arc_next1; + vlib_buffer_t *b0, *b1; + + b0 = *b; + b++; + b1 = *b; + b++; + + /* Prefetch next iteration. */ + if (PREDICT_TRUE (n_left_from >= 4)) + { + vlib_buffer_t *p2, *p3; + + p2 = *b; + p3 = *(b + 1); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD); + } + + next0 = def_next; + next1 = def_next; + + vnet_feature_next (&arc_next0, b0); + vnet_feature_next (&arc_next1, b1); + + vnet_buffer2 (b0)->nat.arc_next = arc_next0; + vnet_buffer2 (b1)->nat.arc_next = arc_next1; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + t->arc_next_index = arc_next0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next1; + t->arc_next_index = arc_next1; + } + } + + n_left_from -= 2; + next[0] = next0; + next[1] = next1; + next += 2; + } + + while (n_left_from > 0) { - 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; + u32 next0; + u32 arc_next0; + vlib_buffer_t *b0; + + b0 = *b; + b++; + + next0 = def_next; + vnet_feature_next (&arc_next0, b0); + vnet_buffer2 (b0)->nat.arc_next = arc_next0; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + t->arc_next_index = arc_next0; + } + + n_left_from--; + next[0] = next0; + next++; } - return 0; + vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts, + frame->n_vectors); + + return frame->n_vectors; } always_inline u8 @@ -91,46 +242,6 @@ is_interface_addr (snat_main_t * sm, vlib_node_runtime_t * node, return 0; } -always_inline u8 -maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index) -{ - if (pool_elts (sm->per_thread_data[thread_index].sessions) >= - sm->max_translations) - return 1; - - return 0; -} - -always_inline void -nat_send_all_to_node (vlib_main_t * vm, u32 * bi_vector, - vlib_node_runtime_t * node, vlib_error_t * error, - u32 next) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - - from = bi_vector; - n_left_from = vec_len (bi_vector); - next_index = node->cached_next_index; - while (n_left_from > 0) - { - 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 = to_next[0] = from[0]; - from += 1; - n_left_from -= 1; - to_next += 1; - n_left_to_next -= 1; - vlib_buffer_t *p0 = vlib_get_buffer (vm, bi0); - if (error) - p0->error = *error; - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } -} - always_inline void user_session_increment (snat_main_t * sm, snat_user_t * u, u8 is_static) { @@ -172,22 +283,29 @@ nat44_delete_session (snat_main_t * sm, snat_session_t * ses, snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data, thread_index); clib_bihash_kv_8_8_t kv, value; - snat_user_key_t u_key; snat_user_t *u; + const snat_user_key_t u_key = { + .addr = ses->in2out.addr, + .fib_index = ses->in2out.fib_index + }; + const u8 u_static = snat_is_session_static (ses); clib_dlist_remove (tsm->list_pool, ses->per_user_index); pool_put_index (tsm->list_pool, ses->per_user_index); + if (sm->endpoint_dependent) + { + clib_dlist_remove (tsm->lru_pool, ses->lru_index); + pool_put_index (tsm->lru_pool, ses->lru_index); + } pool_put (tsm->sessions, ses); vlib_set_simple_counter (&sm->total_sessions, thread_index, 0, pool_elts (tsm->sessions)); - u_key.addr = ses->in2out.addr; - u_key.fib_index = ses->in2out.fib_index; kv.key = u_key.as_u64; if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { u = pool_elt_at_index (tsm->users, value.value); - if (snat_is_session_static (ses)) + if (u_static) u->nstaticsessions--; else u->nsessions--; @@ -196,92 +314,117 @@ nat44_delete_session (snat_main_t * sm, snat_session_t * ses, } } -/** \brief Set TCP session state. - @return 1 if session was closed, otherwise 0 -*/ -always_inline int -nat44_set_tcp_session_state_i2o (snat_main_t * sm, snat_session_t * ses, - tcp_header_t * tcp, u32 thread_index) +always_inline void +nat44_set_tcp_session_state_i2o (snat_main_t * sm, f64 now, + snat_session_t * ses, vlib_buffer_t * b, + u32 thread_index) { - if ((ses->state == 0) && (tcp->flags & TCP_FLAG_RST)) + snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; + u8 tcp_flags = vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags; + u32 tcp_ack_number = vnet_buffer (b)->ip.reass.tcp_ack_number; + u32 tcp_seq_number = vnet_buffer (b)->ip.reass.tcp_seq_number; + if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST)) ses->state = NAT44_SES_RST; - if ((ses->state == NAT44_SES_RST) && !(tcp->flags & TCP_FLAG_RST)) + if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST)) ses->state = 0; - if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) && + if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) && (ses->state & NAT44_SES_O2I_SYN)) ses->state = 0; - if (tcp->flags & TCP_FLAG_SYN) + if (tcp_flags & TCP_FLAG_SYN) ses->state |= NAT44_SES_I2O_SYN; - if (tcp->flags & TCP_FLAG_FIN) + if (tcp_flags & TCP_FLAG_FIN) { - ses->i2o_fin_seq = clib_net_to_host_u32 (tcp->seq_number); + ses->i2o_fin_seq = clib_net_to_host_u32 (tcp_seq_number); ses->state |= NAT44_SES_I2O_FIN; } - if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN)) + if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN)) { - if (clib_net_to_host_u32 (tcp->ack_number) > ses->o2i_fin_seq) - ses->state |= NAT44_SES_O2I_FIN_ACK; + if (clib_net_to_host_u32 (tcp_ack_number) > ses->o2i_fin_seq) + { + ses->state |= NAT44_SES_O2I_FIN_ACK; + if (nat44_is_ses_closed (ses)) + { // if session is now closed, save the timestamp + ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory; + ses->last_lru_update = now; + } + } } - if (nat44_is_ses_closed (ses) - && !(ses->flags & SNAT_SESSION_FLAG_OUTPUT_FEATURE)) + + // move the session to proper LRU + if (ses->state) { - nat_free_session_data (sm, ses, thread_index, 0); - nat44_delete_session (sm, ses, thread_index); - return 1; + ses->lru_head_index = tsm->tcp_trans_lru_head_index; } - return 0; + else + { + ses->lru_head_index = tsm->tcp_estab_lru_head_index; + } + clib_dlist_remove (tsm->lru_pool, ses->lru_index); + clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index); } -always_inline int -nat44_set_tcp_session_state_o2i (snat_main_t * sm, snat_session_t * ses, - tcp_header_t * tcp, u32 thread_index) +always_inline void +nat44_set_tcp_session_state_o2i (snat_main_t * sm, f64 now, + snat_session_t * ses, u8 tcp_flags, + u32 tcp_ack_number, u32 tcp_seq_number, + u32 thread_index) { - if ((ses->state == 0) && (tcp->flags & TCP_FLAG_RST)) + snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; + if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST)) ses->state = NAT44_SES_RST; - if ((ses->state == NAT44_SES_RST) && !(tcp->flags & TCP_FLAG_RST)) + if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST)) ses->state = 0; - if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) && + if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) && (ses->state & NAT44_SES_O2I_SYN)) ses->state = 0; - if (tcp->flags & TCP_FLAG_SYN) + if (tcp_flags & TCP_FLAG_SYN) ses->state |= NAT44_SES_O2I_SYN; - if (tcp->flags & TCP_FLAG_FIN) + if (tcp_flags & TCP_FLAG_FIN) { - ses->o2i_fin_seq = clib_net_to_host_u32 (tcp->seq_number); + ses->o2i_fin_seq = clib_net_to_host_u32 (tcp_seq_number); ses->state |= NAT44_SES_O2I_FIN; } - if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN)) + if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN)) { - if (clib_net_to_host_u32 (tcp->ack_number) > ses->i2o_fin_seq) + if (clib_net_to_host_u32 (tcp_ack_number) > ses->i2o_fin_seq) ses->state |= NAT44_SES_I2O_FIN_ACK; + if (nat44_is_ses_closed (ses)) + { // if session is now closed, save the timestamp + ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory; + ses->last_lru_update = now; + } } - if (nat44_is_ses_closed (ses)) + // move the session to proper LRU + if (ses->state) { - nat_free_session_data (sm, ses, thread_index, 0); - nat44_delete_session (sm, ses, thread_index); - return 1; + ses->lru_head_index = tsm->tcp_trans_lru_head_index; } - return 0; + else + { + ses->lru_head_index = tsm->tcp_estab_lru_head_index; + } + clib_dlist_remove (tsm->lru_pool, ses->lru_index); + clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index); } always_inline u32 nat44_session_get_timeout (snat_main_t * sm, snat_session_t * s) { - switch (s->in2out.protocol) + switch (s->nat_proto) { - case SNAT_PROTOCOL_ICMP: - return sm->icmp_timeout; - case SNAT_PROTOCOL_UDP: - return sm->udp_timeout; - case SNAT_PROTOCOL_TCP: + case NAT_PROTOCOL_ICMP: + return sm->timeouts.icmp; + case NAT_PROTOCOL_UDP: + return sm->timeouts.udp; + case NAT_PROTOCOL_TCP: { if (s->state) - return sm->tcp_transitory_timeout; + return sm->timeouts.tcp.transitory; else - return sm->tcp_established_timeout; + return sm->timeouts.tcp.established; } default: - return sm->udp_timeout; + return sm->timeouts.udp; } return 0; @@ -294,10 +437,12 @@ nat44_session_update_counters (snat_session_t * s, f64 now, uword bytes, s->last_heard = now; s->total_pkts++; s->total_bytes += bytes; +#if 0 nat_ha_sref (&s->out2in.addr, s->out2in.port, &s->ext_host_addr, - s->ext_host_port, s->out2in.protocol, s->out2in.fib_index, + s->ext_host_port, s->nat_proto, s->out2in.fib_index, s->total_pkts, s->total_bytes, thread_index, &s->ha_last_refreshed, now); +#endif } /** \brief Per-user LRU list maintenance */ @@ -305,191 +450,144 @@ always_inline void nat44_session_update_lru (snat_main_t * sm, snat_session_t * s, u32 thread_index) { - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s->per_user_list_head_index, s->per_user_index); + /* don't update too often - timeout is in magnitude of seconds anyway */ + if (s->last_heard > s->last_lru_update + 1) + { + if (!sm->endpoint_dependent) + { + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, + s->per_user_index); + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, + s->per_user_list_head_index, s->per_user_index); + } + else + { + clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool, + s->lru_index); + clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool, + s->lru_head_index, s->lru_index); + } + s->last_lru_update = s->last_heard; + } } always_inline void -make_ed_kv (clib_bihash_kv_16_8_t * kv, ip4_address_t * l_addr, - ip4_address_t * r_addr, u8 proto, u32 fib_index, u16 l_port, - u16 r_port) +init_ed_k (clib_bihash_kv_16_8_t * kv, ip4_address_t l_addr, u16 l_port, + ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto) { - nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key; - - key->l_addr.as_u32 = l_addr->as_u32; - key->r_addr.as_u32 = r_addr->as_u32; - key->fib_index = fib_index; - key->proto = proto; - key->l_port = l_port; - key->r_port = r_port; - - kv->value = ~0ULL; + kv->key[0] = (u64) r_addr.as_u32 << 32 | l_addr.as_u32; + kv->key[1] = + (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto; } always_inline void -make_sm_kv (clib_bihash_kv_8_8_t * kv, ip4_address_t * addr, u8 proto, - u32 fib_index, u16 port) +init_ed_kv (clib_bihash_kv_16_8_t * kv, ip4_address_t l_addr, u16 l_port, + ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto, + u32 thread_index, u32 session_index) { - snat_session_key_t key; - - key.addr.as_u32 = addr->as_u32; - key.port = port; - key.protocol = proto; - key.fib_index = fib_index; - - kv->key = key.as_u64; - kv->value = ~0ULL; + init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto); + kv->value = (u64) thread_index << 32 | session_index; } -static_always_inline int -get_icmp_i2o_ed_key (ip4_header_t * ip0, nat_ed_ses_key_t * p_key0) +always_inline u32 +ed_value_get_thread_index (clib_bihash_kv_16_8_t * value) { - icmp46_header_t *icmp0; - nat_ed_ses_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; + return value->value >> 32; +} - icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - echo0 = (icmp_echo_header_t *) (icmp0 + 1); +always_inline u32 +ed_value_get_session_index (clib_bihash_kv_16_8_t * value) +{ + return value->value & ~(u32) 0; +} - if (!icmp_is_error_message (icmp0)) +always_inline void +split_ed_kv (clib_bihash_kv_16_8_t * kv, + ip4_address_t * l_addr, ip4_address_t * r_addr, u8 * proto, + u32 * fib_index, u16 * l_port, u16 * r_port) +{ + if (l_addr) { - key0.proto = IP_PROTOCOL_ICMP; - key0.l_addr = ip0->src_address; - key0.r_addr = ip0->dst_address; - key0.l_port = echo0->identifier; - key0.r_port = 0; + l_addr->as_u32 = kv->key[0] & (u32) ~ 0; } - else + if (r_addr) { - inner_ip0 = (ip4_header_t *) (echo0 + 1); - l4_header = ip4_next_header (inner_ip0); - key0.proto = inner_ip0->protocol; - key0.r_addr = inner_ip0->src_address; - key0.l_addr = inner_ip0->dst_address; - switch (ip_proto_to_snat_proto (inner_ip0->protocol)) - { - case SNAT_PROTOCOL_ICMP: - inner_icmp0 = (icmp46_header_t *) l4_header; - inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1); - key0.r_port = 0; - key0.l_port = inner_echo0->identifier; - break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - key0.l_port = ((tcp_udp_header_t *) l4_header)->dst_port; - key0.r_port = ((tcp_udp_header_t *) l4_header)->src_port; - break; - default: - return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL; - } + r_addr->as_u32 = kv->key[0] >> 32; + } + if (r_port) + { + *r_port = kv->key[1] >> 48; + } + if (l_port) + { + *l_port = (kv->key[1] >> 32) & (u16) ~ 0; + } + if (fib_index) + { + *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1); + } + if (proto) + { + *proto = kv->key[1] & (u8) ~ 0; } - *p_key0 = key0; - return 0; } - static_always_inline int -get_icmp_o2i_ed_key (ip4_header_t * ip0, nat_ed_ses_key_t * p_key0) +nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0, + ip4_address_t *lookup_saddr, + u16 *lookup_sport, + ip4_address_t *lookup_daddr, + u16 *lookup_dport, u8 *lookup_protocol) { icmp46_header_t *icmp0; - nat_ed_ses_key_t key0; icmp_echo_header_t *echo0, *inner_echo0 = 0; - ip4_header_t *inner_ip0; + 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)) + // avoid warning about unused variables in caller by setting to bogus values + *lookup_sport = 0; + *lookup_dport = 0; + + if (!icmp_type_is_error_message + (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)) { - key0.proto = IP_PROTOCOL_ICMP; - key0.l_addr = ip0->dst_address; - key0.r_addr = ip0->src_address; - key0.l_port = echo0->identifier; - key0.r_port = 0; + *lookup_protocol = IP_PROTOCOL_ICMP; + lookup_saddr->as_u32 = ip0->src_address.as_u32; + *lookup_sport = vnet_buffer (b)->ip.reass.l4_src_port; + lookup_daddr->as_u32 = ip0->dst_address.as_u32; + *lookup_dport = vnet_buffer (b)->ip.reass.l4_dst_port; } else { inner_ip0 = (ip4_header_t *) (echo0 + 1); l4_header = ip4_next_header (inner_ip0); - key0.proto = inner_ip0->protocol; - key0.l_addr = inner_ip0->src_address; - key0.r_addr = inner_ip0->dst_address; - switch (ip_proto_to_snat_proto (inner_ip0->protocol)) + *lookup_protocol = inner_ip0->protocol; + lookup_saddr->as_u32 = inner_ip0->dst_address.as_u32; + lookup_daddr->as_u32 = inner_ip0->src_address.as_u32; + switch (ip_proto_to_nat_proto (inner_ip0->protocol)) { - case SNAT_PROTOCOL_ICMP: + case NAT_PROTOCOL_ICMP: inner_icmp0 = (icmp46_header_t *) l4_header; inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1); - key0.l_port = inner_echo0->identifier; - key0.r_port = 0; + *lookup_sport = inner_echo0->identifier; + *lookup_dport = inner_echo0->identifier; break; - case SNAT_PROTOCOL_UDP: - case SNAT_PROTOCOL_TCP: - key0.l_port = ((tcp_udp_header_t *) l4_header)->src_port; - key0.r_port = ((tcp_udp_header_t *) l4_header)->dst_port; + case NAT_PROTOCOL_UDP: + case NAT_PROTOCOL_TCP: + *lookup_sport = ((tcp_udp_header_t *) l4_header)->dst_port; + *lookup_dport = ((tcp_udp_header_t *) l4_header)->src_port; break; default: - return -1; + return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL; } } - *p_key0 = key0; return 0; } -always_inline void -mss_clamping (snat_main_t * sm, tcp_header_t * tcp, ip_csum_t * sum) -{ - u8 *data; - u8 opt_len, opts_len, kind; - u16 mss; - - if (!(sm->mss_clamping && tcp_syn (tcp))) - return; - - opts_len = (tcp_doff (tcp) << 2) - sizeof (tcp_header_t); - data = (u8 *) (tcp + 1); - for (; opts_len > 0; opts_len -= opt_len, data += opt_len) - { - kind = data[0]; - - if (kind == TCP_OPTION_EOL) - break; - else if (kind == TCP_OPTION_NOOP) - { - opt_len = 1; - continue; - } - else - { - if (opts_len < 2) - return; - opt_len = data[1]; - - if (opt_len < 2 || opt_len > opts_len) - return; - } - - if (kind == TCP_OPTION_MSS) - { - mss = *(u16 *) (data + 2); - if (clib_net_to_host_u16 (mss) > sm->mss_clamping) - { - *sum = - ip_csum_update (*sum, mss, sm->mss_value_net, ip4_header_t, - length); - clib_memcpy_fast (data + 2, &sm->mss_value_net, 2); - } - return; - } - } -} - /** * @brief Check if packet should be translated * @@ -550,18 +648,33 @@ snat_not_translate_fast (snat_main_t * sm, vlib_node_runtime_t * node, return 1; snat_interface_t *i; - pool_foreach (i, sm->interfaces, ( - { - /* NAT packet aimed at outside interface */ - if ((nat_interface_is_outside (i)) - && (sw_if_index == - i->sw_if_index)) return 0;} - )); + /* *INDENT-OFF* */ + pool_foreach (i, sm->interfaces) { + /* NAT packet aimed at outside interface */ + if ((nat_interface_is_outside (i)) && (sw_if_index == i->sw_if_index)) + return 0; + } + /* *INDENT-ON* */ } return 1; } +static_always_inline u16 +snat_random_port (u16 min, u16 max) +{ + snat_main_t *sm = &snat_main; + u32 rwide; + u16 r; + + rwide = random_u32 (&sm->random_seed); + r = rwide & 0xFFFF; + if (r >= min && r <= max) + return r; + + return min + (rwide % (max - min + 1)); +} + #endif /* __included_nat_inlines_h__ */ /*