2 * Copyright (c) 2018 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 * @brief The NAT inline functions
19 #ifndef __included_nat44_ed_inlines_h__
20 #define __included_nat44_ed_inlines_h__
23 #include <vppinfra/clib.h>
24 #include <vnet/fib/ip4_fib.h>
26 #include <nat/lib/log.h>
27 #include <nat/lib/ipfix_logging.h>
28 #include <nat/nat44-ed/nat44_ed.h>
31 init_ed_k (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr,
32 u16 r_port, u32 fib_index, ip_protocol_t proto)
34 kv->key[0] = (u64) r_addr << 32 | l_addr;
36 (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
40 init_ed_kv (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr,
41 u16 r_port, u32 fib_index, u8 proto, u32 thread_index,
44 init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto);
45 kv->value = (u64) thread_index << 32 | session_index;
49 nat44_ed_sm_init_i2o_kv (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port,
50 u32 fib_index, u8 proto, u32 sm_index)
52 return init_ed_kv (kv, addr, port, 0, 0, fib_index, proto, 0, sm_index);
56 nat44_ed_sm_init_o2i_kv (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port,
57 u32 fib_index, u8 proto, u32 sm_index)
59 return init_ed_kv (kv, 0, 0, e_addr, e_port, fib_index, proto, 0, sm_index);
63 nat44_ed_sm_init_i2o_k (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port,
64 u32 fib_index, u8 proto)
66 return nat44_ed_sm_init_i2o_kv (kv, addr, port, fib_index, proto, 0);
70 nat44_ed_sm_init_o2i_k (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port,
71 u32 fib_index, u8 proto)
73 return nat44_ed_sm_init_o2i_kv (kv, e_addr, e_port, fib_index, proto, 0);
77 ed_value_get_thread_index (clib_bihash_kv_16_8_t *value)
79 return value->value >> 32;
83 ed_value_get_session_index (clib_bihash_kv_16_8_t *value)
85 return value->value & ~(u32) 0;
89 split_ed_kv (clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr,
90 ip4_address_t *r_addr, u8 *proto, u32 *fib_index, u16 *l_port,
95 l_addr->as_u32 = kv->key[0] & (u32) ~0;
99 r_addr->as_u32 = kv->key[0] >> 32;
103 *r_port = kv->key[1] >> 48;
107 *l_port = (kv->key[1] >> 32) & (u16) ~0;
111 *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
115 *proto = kv->key[1] & (u8) ~0;
119 static_always_inline int
120 nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0,
121 ip4_address_t *lookup_saddr,
123 ip4_address_t *lookup_daddr,
124 u16 *lookup_dport, u8 *lookup_protocol)
126 icmp46_header_t *icmp0;
127 icmp_echo_header_t *echo0, *inner_echo0 = 0;
128 ip4_header_t *inner_ip0 = 0;
130 icmp46_header_t *inner_icmp0;
132 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
133 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
135 // avoid warning about unused variables in caller by setting to bogus values
139 if (!icmp_type_is_error_message (
140 vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
142 *lookup_protocol = IP_PROTOCOL_ICMP;
143 lookup_saddr->as_u32 = ip0->src_address.as_u32;
144 *lookup_sport = vnet_buffer (b)->ip.reass.l4_src_port;
145 lookup_daddr->as_u32 = ip0->dst_address.as_u32;
146 *lookup_dport = vnet_buffer (b)->ip.reass.l4_dst_port;
150 inner_ip0 = (ip4_header_t *) (echo0 + 1);
151 l4_header = ip4_next_header (inner_ip0);
152 *lookup_protocol = inner_ip0->protocol;
153 lookup_saddr->as_u32 = inner_ip0->dst_address.as_u32;
154 lookup_daddr->as_u32 = inner_ip0->src_address.as_u32;
155 switch (inner_ip0->protocol)
157 case IP_PROTOCOL_ICMP:
158 inner_icmp0 = (icmp46_header_t *) l4_header;
159 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
160 *lookup_sport = inner_echo0->identifier;
161 *lookup_dport = inner_echo0->identifier;
163 case IP_PROTOCOL_UDP:
164 case IP_PROTOCOL_TCP:
165 *lookup_sport = ((tcp_udp_header_t *) l4_header)->dst_port;
166 *lookup_dport = ((tcp_udp_header_t *) l4_header)->src_port;
169 return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
176 nat44_ed_tcp_is_established (nat44_ed_tcp_state_e state)
178 static int lookup[] = {
179 [NAT44_ED_TCP_STATE_CLOSED] = 0,
180 [NAT44_ED_TCP_STATE_SYN_I2O] = 0,
181 [NAT44_ED_TCP_STATE_SYN_O2I] = 0,
182 [NAT44_ED_TCP_STATE_ESTABLISHED] = 1,
183 [NAT44_ED_TCP_STATE_FIN_I2O] = 1,
184 [NAT44_ED_TCP_STATE_FIN_O2I] = 1,
185 [NAT44_ED_TCP_STATE_RST_TRANS] = 0,
186 [NAT44_ED_TCP_STATE_FIN_TRANS] = 0,
187 [NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O] = 0,
188 [NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I] = 0,
189 [NAT44_ED_TCP_N_STATE] = 0,
191 ASSERT (state <= ARRAY_LEN (lookup));
192 return lookup[state];
196 nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s)
200 case IP_PROTOCOL_ICMP:
202 case IP_PROTOCOL_ICMP6:
203 return sm->timeouts.icmp;
204 case IP_PROTOCOL_UDP:
205 return sm->timeouts.udp;
206 case IP_PROTOCOL_TCP:
208 if (nat44_ed_tcp_is_established (s->tcp_state))
209 return sm->timeouts.tcp.established;
211 return sm->timeouts.tcp.transitory;
214 return sm->timeouts.udp;
220 static_always_inline u8
221 nat44_ed_maximum_sessions_exceeded (snat_main_t *sm, u32 fib_index,
225 translations = pool_elts (sm->per_thread_data[thread_index].sessions);
226 if (vec_len (sm->max_translations_per_fib) <= fib_index)
228 return translations >= sm->max_translations_per_fib[fib_index];
231 static_always_inline int
232 nat_ed_lru_insert (snat_main_per_thread_data_t *tsm, snat_session_t *s,
235 dlist_elt_t *lru_list_elt;
236 pool_get (tsm->lru_pool, lru_list_elt);
237 s->lru_index = lru_list_elt - tsm->lru_pool;
240 case IP_PROTOCOL_UDP:
241 s->lru_head_index = tsm->udp_lru_head_index;
243 case IP_PROTOCOL_TCP:
244 s->lru_head_index = tsm->tcp_trans_lru_head_index;
246 case IP_PROTOCOL_ICMP:
247 s->lru_head_index = tsm->icmp_lru_head_index;
250 s->lru_head_index = tsm->unk_proto_lru_head_index;
253 clib_dlist_addtail (tsm->lru_pool, s->lru_head_index, s->lru_index);
254 lru_list_elt->value = s - tsm->sessions;
255 s->last_lru_update = now;
259 static_always_inline void
260 nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
262 init_ed_k (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32,
263 f->match.dport, f->match.fib_index, f->match.proto);
266 static_always_inline void
267 nat_6t_flow_to_ed_kv (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f,
268 u32 thread_idx, u32 session_idx)
270 init_ed_kv (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32,
271 f->match.dport, f->match.fib_index, f->match.proto, thread_idx,
275 static_always_inline int
276 nat_ed_ses_i2o_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
277 snat_session_t *s, int is_add)
279 snat_main_per_thread_data_t *tsm =
280 vec_elt_at_index (sm->per_thread_data, thread_idx);
281 clib_bihash_kv_16_8_t kv;
284 nat_6t_flow_to_ed_k (&kv, &s->i2o);
288 nat_6t_flow_to_ed_kv (&kv, &s->i2o, thread_idx, s - tsm->sessions);
289 nat_6t_l3_l4_csum_calc (&s->i2o);
292 ASSERT (thread_idx == s->thread_index);
293 return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
296 static_always_inline int
297 nat_ed_ses_o2i_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
298 snat_session_t *s, int is_add)
300 snat_main_per_thread_data_t *tsm =
301 vec_elt_at_index (sm->per_thread_data, thread_idx);
302 clib_bihash_kv_16_8_t kv;
305 nat_6t_flow_to_ed_k (&kv, &s->o2i);
309 nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions);
310 if (!(s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
312 if (nat44_ed_sm_o2i_lookup (sm, s->o2i.match.daddr,
313 s->o2i.match.dport, 0,
319 nat_6t_l3_l4_csum_calc (&s->o2i);
321 ASSERT (thread_idx == s->thread_index);
322 return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
326 nat_ed_session_delete (snat_main_t *sm, snat_session_t *ses, u32 thread_index,
328 /* delete from global LRU list */)
330 snat_main_per_thread_data_t *tsm =
331 vec_elt_at_index (sm->per_thread_data, thread_index);
335 clib_dlist_remove (tsm->lru_pool, ses->lru_index);
337 pool_put_index (tsm->lru_pool, ses->lru_index);
338 if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, ses, 0))
339 nat_elog_warn (sm, "flow hash del failed");
340 if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, ses, 0))
341 nat_elog_warn (sm, "flow hash del failed");
342 pool_put (tsm->sessions, ses);
343 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
344 pool_elts (tsm->sessions));
347 static_always_inline int
348 nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now,
351 snat_session_t *s = NULL;
352 dlist_elt_t *oldest_elt;
353 f64 sess_timeout_time;
355 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
356 oldest_index = clib_dlist_remove_head (tsm->lru_pool, head_index);
357 if (~0 != oldest_index)
359 oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
360 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
363 s->last_heard + (f64) nat44_session_get_timeout (sm, s);
364 if (now >= sess_timeout_time)
366 nat44_ed_free_session_data (sm, s, thread_index, 0);
367 nat_ed_session_delete (sm, s, thread_index, 0);
372 clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
378 static_always_inline int
379 nat_lru_free_one (snat_main_t *sm, int thread_index, f64 now)
381 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
384 if ((rc = nat_lru_free_one_with_head (sm, thread_index, now, \
385 tsm->p##_lru_head_index))) \
398 static_always_inline snat_session_t *
399 nat_ed_session_alloc (snat_main_t *sm, u32 thread_index, f64 now, u8 proto)
402 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
404 nat_lru_free_one (sm, thread_index, now);
406 pool_get (tsm->sessions, s);
407 clib_memset (s, 0, sizeof (*s));
409 nat_ed_lru_insert (tsm, s, now, proto);
411 s->ha_last_refreshed = now;
412 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
413 pool_elts (tsm->sessions));
414 #if CLIB_ASSERT_ENABLE
415 s->thread_index = thread_index;
421 static_always_inline void
422 per_vrf_sessions_cleanup (u32 thread_index)
424 snat_main_t *sm = &snat_main;
425 snat_main_per_thread_data_t *tsm =
426 vec_elt_at_index (sm->per_thread_data, thread_index);
427 per_vrf_sessions_t *per_vrf_sessions;
428 u32 *to_free = 0, *i;
430 vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
432 if (per_vrf_sessions->expired)
434 if (per_vrf_sessions->ses_count == 0)
436 vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_vec);
441 if (vec_len (to_free))
443 vec_foreach (i, to_free)
445 vec_del1 (tsm->per_vrf_sessions_vec, *i);
453 static_always_inline void
454 per_vrf_sessions_register_session (snat_session_t *s, u32 thread_index)
456 snat_main_t *sm = &snat_main;
457 snat_main_per_thread_data_t *tsm =
458 vec_elt_at_index (sm->per_thread_data, thread_index);
459 per_vrf_sessions_t *per_vrf_sessions;
461 per_vrf_sessions_cleanup (thread_index);
463 // s->per_vrf_sessions_index == ~0 ... reuse of old session
465 vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
467 // ignore already expired registrations
468 if (per_vrf_sessions->expired)
471 if ((s->in2out.fib_index == per_vrf_sessions->rx_fib_index) &&
472 (s->out2in.fib_index == per_vrf_sessions->tx_fib_index))
476 if ((s->in2out.fib_index == per_vrf_sessions->tx_fib_index) &&
477 (s->out2in.fib_index == per_vrf_sessions->rx_fib_index))
483 // create a new registration
484 vec_add2 (tsm->per_vrf_sessions_vec, per_vrf_sessions, 1);
485 clib_memset (per_vrf_sessions, 0, sizeof (*per_vrf_sessions));
487 per_vrf_sessions->rx_fib_index = s->in2out.fib_index;
488 per_vrf_sessions->tx_fib_index = s->out2in.fib_index;
491 s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_vec;
492 per_vrf_sessions->ses_count++;
496 static_always_inline void
497 per_vrf_sessions_unregister_session (snat_session_t *s, u32 thread_index)
499 snat_main_t *sm = &snat_main;
500 snat_main_per_thread_data_t *tsm;
501 per_vrf_sessions_t *per_vrf_sessions;
503 ASSERT (s->per_vrf_sessions_index != ~0);
505 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
507 vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
509 ASSERT (per_vrf_sessions->ses_count != 0);
511 per_vrf_sessions->ses_count--;
512 s->per_vrf_sessions_index = ~0;
516 static_always_inline u8
517 per_vrf_sessions_is_expired (snat_session_t *s, u32 thread_index)
519 snat_main_t *sm = &snat_main;
520 snat_main_per_thread_data_t *tsm;
521 per_vrf_sessions_t *per_vrf_sessions;
523 ASSERT (s->per_vrf_sessions_index != ~0);
525 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
527 vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
528 return per_vrf_sessions->expired;
531 static_always_inline void
532 nat_6t_flow_init (nat_6t_flow_t *f, u32 thread_idx, ip4_address_t saddr,
533 u16 sport, ip4_address_t daddr, u16 dport, u32 fib_index,
534 u8 proto, u32 session_idx)
536 clib_memset (f, 0, sizeof (*f));
537 f->match.saddr = saddr;
538 f->match.sport = sport;
539 f->match.daddr = daddr;
540 f->match.dport = dport;
541 f->match.proto = proto;
542 f->match.fib_index = fib_index;
545 static_always_inline void
546 nat_6t_i2o_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
547 ip4_address_t saddr, u16 sport, ip4_address_t daddr,
548 u16 dport, u32 fib_index, u8 proto)
550 snat_main_per_thread_data_t *tsm =
551 vec_elt_at_index (sm->per_thread_data, thread_idx);
552 nat_6t_flow_init (&s->i2o, thread_idx, saddr, sport, daddr, dport, fib_index,
553 proto, s - tsm->sessions);
556 static_always_inline void
557 nat_6t_o2i_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
558 ip4_address_t saddr, u16 sport, ip4_address_t daddr,
559 u16 dport, u32 fib_index, u8 proto)
561 snat_main_per_thread_data_t *tsm =
562 vec_elt_at_index (sm->per_thread_data, thread_idx);
563 nat_6t_flow_init (&s->o2i, thread_idx, saddr, sport, daddr, dport, fib_index,
564 proto, s - tsm->sessions);
567 static_always_inline int
568 nat_6t_t_eq (nat_6t_t *t1, nat_6t_t *t2)
570 return t1->as_u64[0] == t2->as_u64[0] && t1->as_u64[1] == t2->as_u64[1];
574 nat_pre_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
575 vlib_frame_t *frame, u32 def_next)
577 u32 n_left_from, *from;
579 from = vlib_frame_vector_args (frame);
580 n_left_from = frame->n_vectors;
582 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
583 u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
584 vlib_get_buffers (vm, from, b, n_left_from);
586 while (n_left_from >= 2)
589 u32 arc_next0, arc_next1;
590 vlib_buffer_t *b0, *b1;
597 /* Prefetch next iteration. */
598 if (PREDICT_TRUE (n_left_from >= 4))
600 vlib_buffer_t *p2, *p3;
605 vlib_prefetch_buffer_header (p2, LOAD);
606 vlib_prefetch_buffer_header (p3, LOAD);
608 clib_prefetch_load (p2->data);
609 clib_prefetch_load (p3->data);
615 vnet_feature_next (&arc_next0, b0);
616 vnet_feature_next (&arc_next1, b1);
618 vnet_buffer2 (b0)->nat.arc_next = arc_next0;
619 vnet_buffer2 (b1)->nat.arc_next = arc_next1;
621 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
623 if (b0->flags & VLIB_BUFFER_IS_TRACED)
625 nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
626 t->next_index = next0;
627 t->arc_next_index = arc_next0;
629 if (b1->flags & VLIB_BUFFER_IS_TRACED)
631 nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
632 t->next_index = next1;
633 t->arc_next_index = arc_next1;
643 while (n_left_from > 0)
653 vnet_feature_next (&arc_next0, b0);
654 vnet_buffer2 (b0)->nat.arc_next = arc_next0;
656 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
657 (b0->flags & VLIB_BUFFER_IS_TRACED)))
659 nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
660 t->next_index = next0;
661 t->arc_next_index = arc_next0;
668 vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
671 return frame->n_vectors;
674 static_always_inline u16
675 snat_random_port (u16 min, u16 max)
677 snat_main_t *sm = &snat_main;
681 rwide = random_u32 (&sm->random_seed);
683 if (r >= min && r <= max)
686 return min + (rwide % (max - min + 1));
690 is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node,
691 u32 sw_if_index0, u32 ip4_addr)
693 snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
696 if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
698 ip_lookup_main_t *lm = &sm->ip4_main->lookup_main;
699 ip_interface_address_t *ia;
702 rt->cached_sw_if_index = ~0;
703 hash_free (rt->cached_presence_by_ip4_address);
705 foreach_ip_interface_address (
706 lm, ia, sw_if_index0, 1 /* honor unnumbered */, ({
707 a = ip_interface_address_get_address (lm, ia);
708 hash_set (rt->cached_presence_by_ip4_address, a->as_u32, 1);
709 rt->cached_sw_if_index = sw_if_index0;
712 if (rt->cached_sw_if_index == ~0)
716 ip4_addr_exists = !!hash_get (rt->cached_presence_by_ip4_address, ip4_addr);
717 if (PREDICT_FALSE (ip4_addr_exists))
724 nat44_ed_session_reopen (u32 thread_index, snat_session_t *s)
726 nat_syslog_nat44_sdel (0, s->in2out.fib_index, &s->in2out.addr,
727 s->in2out.port, &s->ext_host_nat_addr,
728 s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
729 &s->ext_host_addr, s->ext_host_port, s->proto,
730 nat44_ed_is_twice_nat_session (s));
732 nat_ipfix_logging_nat44_ses_delete (
733 thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
734 s->in2out.port, s->out2in.port, s->in2out.fib_index);
735 nat_ipfix_logging_nat44_ses_create (
736 thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
737 s->in2out.port, s->out2in.port, s->in2out.fib_index);
739 nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
740 s->in2out.port, &s->ext_host_nat_addr,
741 s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
742 &s->ext_host_addr, s->ext_host_port, s->proto, 0);
748 nat44_ed_init_tcp_state_stable (snat_main_t *sm)
750 /* first make sure whole table is initialised in a way where state
751 * is not changed, then define special cases */
752 nat44_ed_tcp_state_e s;
753 for (s = 0; s < NAT44_ED_TCP_N_STATE; ++s)
756 for (i = 0; i < NAT44_ED_N_DIR; ++i)
759 for (j = 0; j < NAT44_ED_TCP_N_FLAG; ++j)
761 sm->tcp_state_change_table[s][i][j] = s;
766 /* CLOSED and any kind of SYN -> HALF-OPEN */
767 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
768 [NAT44_ED_TCP_FLAG_SYN] =
769 NAT44_ED_TCP_STATE_SYN_I2O;
770 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
771 [NAT44_ED_TCP_FLAG_SYN] =
772 NAT44_ED_TCP_STATE_SYN_O2I;
773 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
774 [NAT44_ED_TCP_FLAG_SYNFIN] =
775 NAT44_ED_TCP_STATE_SYN_I2O;
776 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
777 [NAT44_ED_TCP_FLAG_SYNFIN] =
778 NAT44_ED_TCP_STATE_SYN_O2I;
779 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
780 [NAT44_ED_TCP_FLAG_SYNFINRST] =
781 NAT44_ED_TCP_STATE_SYN_I2O;
782 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
783 [NAT44_ED_TCP_FLAG_SYNFINRST] =
784 NAT44_ED_TCP_STATE_SYN_O2I;
786 /* HALF-OPEN and any kind of SYN in right direction -> ESTABLISHED */
787 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
788 [NAT44_ED_TCP_FLAG_SYN] =
789 NAT44_ED_TCP_STATE_ESTABLISHED;
790 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
791 [NAT44_ED_TCP_FLAG_SYN] =
792 NAT44_ED_TCP_STATE_ESTABLISHED;
793 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
794 [NAT44_ED_TCP_FLAG_SYNFIN] =
795 NAT44_ED_TCP_STATE_ESTABLISHED;
796 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
797 [NAT44_ED_TCP_FLAG_SYNFIN] =
798 NAT44_ED_TCP_STATE_ESTABLISHED;
799 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
800 [NAT44_ED_TCP_FLAG_SYNFINRST] =
801 NAT44_ED_TCP_STATE_ESTABLISHED;
802 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
803 [NAT44_ED_TCP_FLAG_SYNFINRST] =
804 NAT44_ED_TCP_STATE_ESTABLISHED;
806 /* ESTABLISHED and any kind of RST -> RST_TRANS */
807 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
808 [NAT44_ED_TCP_FLAG_RST] =
809 NAT44_ED_TCP_STATE_RST_TRANS;
810 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
811 [NAT44_ED_TCP_FLAG_RST] =
812 NAT44_ED_TCP_STATE_RST_TRANS;
813 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
814 [NAT44_ED_TCP_FLAG_SYNRST] =
815 NAT44_ED_TCP_STATE_RST_TRANS;
816 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
817 [NAT44_ED_TCP_FLAG_SYNRST] =
818 NAT44_ED_TCP_STATE_RST_TRANS;
819 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
820 [NAT44_ED_TCP_FLAG_FINRST] =
821 NAT44_ED_TCP_STATE_RST_TRANS;
822 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
823 [NAT44_ED_TCP_FLAG_FINRST] =
824 NAT44_ED_TCP_STATE_RST_TRANS;
825 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
826 [NAT44_ED_TCP_FLAG_SYNFINRST] =
827 NAT44_ED_TCP_STATE_RST_TRANS;
828 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
829 [NAT44_ED_TCP_FLAG_SYNFINRST] =
830 NAT44_ED_TCP_STATE_RST_TRANS;
832 /* ESTABLISHED and any kind of FIN without RST -> HALF-CLOSED */
833 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
834 [NAT44_ED_TCP_FLAG_FIN] =
835 NAT44_ED_TCP_STATE_FIN_I2O;
836 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
837 [NAT44_ED_TCP_FLAG_FIN] =
838 NAT44_ED_TCP_STATE_FIN_O2I;
839 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
840 [NAT44_ED_TCP_FLAG_SYNFIN] =
841 NAT44_ED_TCP_STATE_FIN_I2O;
842 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
843 [NAT44_ED_TCP_FLAG_SYNFIN] =
844 NAT44_ED_TCP_STATE_FIN_O2I;
846 /* HALF-CLOSED and any kind of FIN -> FIN_TRANS */
847 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
848 [NAT44_ED_TCP_FLAG_FIN] =
849 NAT44_ED_TCP_STATE_FIN_TRANS;
850 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
851 [NAT44_ED_TCP_FLAG_FIN] =
852 NAT44_ED_TCP_STATE_FIN_TRANS;
853 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
854 [NAT44_ED_TCP_FLAG_SYNFIN] =
855 NAT44_ED_TCP_STATE_FIN_TRANS;
856 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
857 [NAT44_ED_TCP_FLAG_SYNFIN] =
858 NAT44_ED_TCP_STATE_FIN_TRANS;
859 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
860 [NAT44_ED_TCP_FLAG_FINRST] =
861 NAT44_ED_TCP_STATE_FIN_TRANS;
862 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
863 [NAT44_ED_TCP_FLAG_FINRST] =
864 NAT44_ED_TCP_STATE_FIN_TRANS;
865 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
866 [NAT44_ED_TCP_FLAG_SYNFINRST] =
867 NAT44_ED_TCP_STATE_FIN_TRANS;
868 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
869 [NAT44_ED_TCP_FLAG_SYNFINRST] =
870 NAT44_ED_TCP_STATE_FIN_TRANS;
872 /* RST_TRANS and anything non-RST -> ESTABLISHED */
873 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
874 [NAT44_ED_TCP_FLAG_NONE] =
875 NAT44_ED_TCP_STATE_ESTABLISHED;
876 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
877 [NAT44_ED_TCP_FLAG_NONE] =
878 NAT44_ED_TCP_STATE_ESTABLISHED;
879 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
880 [NAT44_ED_TCP_FLAG_SYN] =
881 NAT44_ED_TCP_STATE_ESTABLISHED;
882 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
883 [NAT44_ED_TCP_FLAG_SYN] =
884 NAT44_ED_TCP_STATE_ESTABLISHED;
885 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
886 [NAT44_ED_TCP_FLAG_FIN] =
887 NAT44_ED_TCP_STATE_ESTABLISHED;
888 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
889 [NAT44_ED_TCP_FLAG_FIN] =
890 NAT44_ED_TCP_STATE_ESTABLISHED;
891 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
892 [NAT44_ED_TCP_FLAG_SYNFIN] =
893 NAT44_ED_TCP_STATE_ESTABLISHED;
894 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
895 [NAT44_ED_TCP_FLAG_SYNFIN] =
896 NAT44_ED_TCP_STATE_ESTABLISHED;
898 /* FIN_TRANS and any kind of SYN -> HALF-REOPEN */
899 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
900 [NAT44_ED_TCP_FLAG_SYN] =
901 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
902 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
903 [NAT44_ED_TCP_FLAG_SYN] =
904 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
905 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
906 [NAT44_ED_TCP_FLAG_SYNRST] =
907 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
908 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
909 [NAT44_ED_TCP_FLAG_SYNRST] =
910 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
911 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
912 [NAT44_ED_TCP_FLAG_SYNFIN] =
913 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
914 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
915 [NAT44_ED_TCP_FLAG_SYNFIN] =
916 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
917 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
918 [NAT44_ED_TCP_FLAG_SYNFINRST] =
919 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
920 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
921 [NAT44_ED_TCP_FLAG_SYNFINRST] =
922 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
924 /* HALF-REOPEN and any kind of SYN in right direction -> ESTABLISHED */
925 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
926 [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYN] =
927 NAT44_ED_TCP_STATE_ESTABLISHED;
928 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
929 [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYN] =
930 NAT44_ED_TCP_STATE_ESTABLISHED;
931 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
932 [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNRST] =
933 NAT44_ED_TCP_STATE_ESTABLISHED;
934 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
935 [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNRST] =
936 NAT44_ED_TCP_STATE_ESTABLISHED;
937 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
938 [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNFIN] =
939 NAT44_ED_TCP_STATE_ESTABLISHED;
940 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
941 [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNFIN] =
942 NAT44_ED_TCP_STATE_ESTABLISHED;
943 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
944 [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNFINRST] =
945 NAT44_ED_TCP_STATE_ESTABLISHED;
946 sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
947 [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNFINRST] =
948 NAT44_ED_TCP_STATE_ESTABLISHED;
951 /* TCP state tracking according to RFC 7857 (and RFC 6146, which is referenced
952 * by RFC 7857). Our implementation also goes beyond by supporting creation of
953 * a new session while old session is in transitory timeout after seeing FIN
954 * packets from both sides. */
956 nat44_set_tcp_session_state (snat_main_t *sm, f64 now, snat_session_t *ses,
957 u8 tcp_flags, u32 thread_index,
960 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
961 nat44_ed_tcp_flag_e flags =
962 tcp_flags & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST);
964 u8 old_state = ses->tcp_state;
965 ses->tcp_state = sm->tcp_state_change_table[ses->tcp_state][dir][flags];
967 if (old_state != ses->tcp_state)
969 if (nat44_ed_tcp_is_established (ses->tcp_state))
971 if (NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O == old_state ||
972 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I == old_state)
974 nat44_ed_session_reopen (thread_index, ses);
976 ses->lru_head_index = tsm->tcp_estab_lru_head_index;
980 if (NAT44_ED_TCP_STATE_ESTABLISHED == old_state)
981 { // need to update last heard otherwise session might get
982 // immediately timed out if it has been idle longer than
983 // transitory timeout
984 ses->last_heard = now;
986 ses->lru_head_index = tsm->tcp_trans_lru_head_index;
988 ses->last_lru_update = now;
989 clib_dlist_remove (tsm->lru_pool, ses->lru_index);
990 clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
995 nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses,
996 u8 tcp_flags, u32 thread_index)
998 return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
1003 nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses,
1004 u8 tcp_flags, u32 thread_index)
1006 return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
1011 nat44_session_update_counters (snat_session_t *s, f64 now, uword bytes,
1014 if (NAT44_ED_TCP_STATE_RST_TRANS != s->tcp_state &&
1015 NAT44_ED_TCP_STATE_FIN_TRANS != s->tcp_state &&
1016 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O != s->tcp_state &&
1017 NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I != s->tcp_state)
1019 s->last_heard = now;
1022 s->total_bytes += bytes;
1025 /** \brief Per-user LRU list maintenance */
1027 nat44_session_update_lru (snat_main_t *sm, snat_session_t *s, u32 thread_index)
1029 /* don't update too often - timeout is in magnitude of seconds anyway */
1030 if (s->last_heard > s->last_lru_update + 1)
1032 clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
1034 clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool,
1035 s->lru_head_index, s->lru_index);
1036 s->last_lru_update = s->last_heard;
1040 static_always_inline int
1041 nat44_ed_is_unk_proto (u8 proto)
1043 static const int lookup_table[256] = {
1044 [IP_PROTOCOL_TCP] = 1,
1045 [IP_PROTOCOL_UDP] = 1,
1046 [IP_PROTOCOL_ICMP] = 1,
1047 [IP_PROTOCOL_ICMP6] = 1,
1050 return 1 - lookup_table[proto];
1053 #endif /* __included_nat44_ed_inlines_h__ */
1056 * fd.io coding-style-patch-verification: ON
1059 * eval: (c-set-style "gnu")