nat: TCP state tracking based on RFC 7857/RFC 6146
[vpp.git] / src / plugins / nat / nat44-ed / nat44_ed_inlines.h
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 /**
16  * @brief The NAT inline functions
17  */
18
19 #ifndef __included_nat44_ed_inlines_h__
20 #define __included_nat44_ed_inlines_h__
21
22 #include <float.h>
23 #include <vppinfra/clib.h>
24 #include <vnet/fib/ip4_fib.h>
25
26 #include <nat/lib/log.h>
27 #include <nat/lib/ipfix_logging.h>
28 #include <nat/nat44-ed/nat44_ed.h>
29
30 always_inline void
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)
33 {
34   kv->key[0] = (u64) r_addr << 32 | l_addr;
35   kv->key[1] =
36     (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
37 }
38
39 always_inline void
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,
42             u32 session_index)
43 {
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;
46 }
47
48 always_inline void
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)
51 {
52   return init_ed_kv (kv, addr, port, 0, 0, fib_index, proto, 0, sm_index);
53 }
54
55 always_inline void
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)
58 {
59   return init_ed_kv (kv, 0, 0, e_addr, e_port, fib_index, proto, 0, sm_index);
60 }
61
62 always_inline void
63 nat44_ed_sm_init_i2o_k (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port,
64                         u32 fib_index, u8 proto)
65 {
66   return nat44_ed_sm_init_i2o_kv (kv, addr, port, fib_index, proto, 0);
67 }
68
69 always_inline void
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)
72 {
73   return nat44_ed_sm_init_o2i_kv (kv, e_addr, e_port, fib_index, proto, 0);
74 }
75
76 always_inline u32
77 ed_value_get_thread_index (clib_bihash_kv_16_8_t *value)
78 {
79   return value->value >> 32;
80 }
81
82 always_inline u32
83 ed_value_get_session_index (clib_bihash_kv_16_8_t *value)
84 {
85   return value->value & ~(u32) 0;
86 }
87
88 always_inline void
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,
91              u16 *r_port)
92 {
93   if (l_addr)
94     {
95       l_addr->as_u32 = kv->key[0] & (u32) ~0;
96     }
97   if (r_addr)
98     {
99       r_addr->as_u32 = kv->key[0] >> 32;
100     }
101   if (r_port)
102     {
103       *r_port = kv->key[1] >> 48;
104     }
105   if (l_port)
106     {
107       *l_port = (kv->key[1] >> 32) & (u16) ~0;
108     }
109   if (fib_index)
110     {
111       *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
112     }
113   if (proto)
114     {
115       *proto = kv->key[1] & (u8) ~0;
116     }
117 }
118
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,
122                                     u16 *lookup_sport,
123                                     ip4_address_t *lookup_daddr,
124                                     u16 *lookup_dport, u8 *lookup_protocol)
125 {
126   icmp46_header_t *icmp0;
127   icmp_echo_header_t *echo0, *inner_echo0 = 0;
128   ip4_header_t *inner_ip0 = 0;
129   void *l4_header = 0;
130   icmp46_header_t *inner_icmp0;
131
132   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
133   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
134
135   // avoid warning about unused variables in caller by setting to bogus values
136   *lookup_sport = 0;
137   *lookup_dport = 0;
138
139   if (!icmp_type_is_error_message (
140         vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
141     {
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;
147     }
148   else
149     {
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)
156         {
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;
162           break;
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;
167           break;
168         default:
169           return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
170         }
171     }
172   return 0;
173 }
174
175 always_inline int
176 nat44_ed_tcp_is_established (nat44_ed_tcp_state_e state)
177 {
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,
190   };
191   ASSERT (state <= ARRAY_LEN (lookup));
192   return lookup[state];
193 }
194
195 always_inline u32
196 nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s)
197 {
198   switch (s->proto)
199     {
200     case IP_PROTOCOL_ICMP:
201       /* fallthrough */
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:
207       {
208         if (nat44_ed_tcp_is_established (s->tcp_state))
209           return sm->timeouts.tcp.established;
210         else
211           return sm->timeouts.tcp.transitory;
212       }
213     default:
214       return sm->timeouts.udp;
215     }
216
217   return 0;
218 }
219
220 static_always_inline u8
221 nat44_ed_maximum_sessions_exceeded (snat_main_t *sm, u32 fib_index,
222                                     u32 thread_index)
223 {
224   u32 translations;
225   translations = pool_elts (sm->per_thread_data[thread_index].sessions);
226   if (vec_len (sm->max_translations_per_fib) <= fib_index)
227     fib_index = 0;
228   return translations >= sm->max_translations_per_fib[fib_index];
229 }
230
231 static_always_inline int
232 nat_ed_lru_insert (snat_main_per_thread_data_t *tsm, snat_session_t *s,
233                    f64 now, u8 proto)
234 {
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;
238   switch (proto)
239     {
240     case IP_PROTOCOL_UDP:
241       s->lru_head_index = tsm->udp_lru_head_index;
242       break;
243     case IP_PROTOCOL_TCP:
244       s->lru_head_index = tsm->tcp_trans_lru_head_index;
245       break;
246     case IP_PROTOCOL_ICMP:
247       s->lru_head_index = tsm->icmp_lru_head_index;
248       break;
249     default:
250       s->lru_head_index = tsm->unk_proto_lru_head_index;
251       break;
252     }
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;
256   return 1;
257 }
258
259 static_always_inline void
260 nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
261 {
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);
264 }
265
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)
269 {
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,
272               session_idx);
273 }
274
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)
278 {
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;
282   if (0 == is_add)
283     {
284       nat_6t_flow_to_ed_k (&kv, &s->i2o);
285     }
286   else
287     {
288       nat_6t_flow_to_ed_kv (&kv, &s->i2o, thread_idx, s - tsm->sessions);
289       nat_6t_l3_l4_csum_calc (&s->i2o);
290     }
291
292   ASSERT (thread_idx == s->thread_index);
293   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
294 }
295
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)
299 {
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;
303   if (0 == is_add)
304     {
305       nat_6t_flow_to_ed_k (&kv, &s->o2i);
306     }
307   else
308     {
309       nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions);
310       if (!(s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
311         {
312           if (nat44_ed_sm_o2i_lookup (sm, s->o2i.match.daddr,
313                                       s->o2i.match.dport, 0,
314                                       s->o2i.match.proto))
315             {
316               return -1;
317             }
318         }
319       nat_6t_l3_l4_csum_calc (&s->o2i);
320     }
321   ASSERT (thread_idx == s->thread_index);
322   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
323 }
324
325 always_inline void
326 nat_ed_session_delete (snat_main_t *sm, snat_session_t *ses, u32 thread_index,
327                        int lru_delete
328                        /* delete from global LRU list */)
329 {
330   snat_main_per_thread_data_t *tsm =
331     vec_elt_at_index (sm->per_thread_data, thread_index);
332
333   if (lru_delete)
334     {
335       clib_dlist_remove (tsm->lru_pool, ses->lru_index);
336     }
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));
345 }
346
347 static_always_inline int
348 nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now,
349                             u32 head_index)
350 {
351   snat_session_t *s = NULL;
352   dlist_elt_t *oldest_elt;
353   f64 sess_timeout_time;
354   u32 oldest_index;
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)
358     {
359       oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
360       s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
361
362       sess_timeout_time =
363         s->last_heard + (f64) nat44_session_get_timeout (sm, s);
364       if (now >= sess_timeout_time)
365         {
366           nat44_ed_free_session_data (sm, s, thread_index, 0);
367           nat_ed_session_delete (sm, s, thread_index, 0);
368           return 1;
369         }
370       else
371         {
372           clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
373         }
374     }
375   return 0;
376 }
377
378 static_always_inline int
379 nat_lru_free_one (snat_main_t *sm, int thread_index, f64 now)
380 {
381   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
382   int rc = 0;
383 #define _(p)                                                                  \
384   if ((rc = nat_lru_free_one_with_head (sm, thread_index, now,                \
385                                         tsm->p##_lru_head_index)))            \
386     {                                                                         \
387       return rc;                                                              \
388     }
389   _ (tcp_trans);
390   _ (udp);
391   _ (unk_proto);
392   _ (icmp);
393   _ (tcp_estab);
394 #undef _
395   return 0;
396 }
397
398 static_always_inline snat_session_t *
399 nat_ed_session_alloc (snat_main_t *sm, u32 thread_index, f64 now, u8 proto)
400 {
401   snat_session_t *s;
402   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
403
404   nat_lru_free_one (sm, thread_index, now);
405
406   pool_get (tsm->sessions, s);
407   clib_memset (s, 0, sizeof (*s));
408
409   nat_ed_lru_insert (tsm, s, now, proto);
410
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;
416 #endif
417   return s;
418 }
419
420 // slow path
421 static_always_inline void
422 per_vrf_sessions_cleanup (u32 thread_index)
423 {
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;
429
430   vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
431     {
432       if (per_vrf_sessions->expired)
433         {
434           if (per_vrf_sessions->ses_count == 0)
435             {
436               vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_vec);
437             }
438         }
439     }
440
441   if (vec_len (to_free))
442     {
443       vec_foreach (i, to_free)
444         {
445           vec_del1 (tsm->per_vrf_sessions_vec, *i);
446         }
447     }
448
449   vec_free (to_free);
450 }
451
452 // slow path
453 static_always_inline void
454 per_vrf_sessions_register_session (snat_session_t *s, u32 thread_index)
455 {
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;
460
461   per_vrf_sessions_cleanup (thread_index);
462
463   // s->per_vrf_sessions_index == ~0 ... reuse of old session
464
465   vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
466     {
467       // ignore already expired registrations
468       if (per_vrf_sessions->expired)
469         continue;
470
471       if ((s->in2out.fib_index == per_vrf_sessions->rx_fib_index) &&
472           (s->out2in.fib_index == per_vrf_sessions->tx_fib_index))
473         {
474           goto done;
475         }
476       if ((s->in2out.fib_index == per_vrf_sessions->tx_fib_index) &&
477           (s->out2in.fib_index == per_vrf_sessions->rx_fib_index))
478         {
479           goto done;
480         }
481     }
482
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));
486
487   per_vrf_sessions->rx_fib_index = s->in2out.fib_index;
488   per_vrf_sessions->tx_fib_index = s->out2in.fib_index;
489
490 done:
491   s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_vec;
492   per_vrf_sessions->ses_count++;
493 }
494
495 // fast path
496 static_always_inline void
497 per_vrf_sessions_unregister_session (snat_session_t *s, u32 thread_index)
498 {
499   snat_main_t *sm = &snat_main;
500   snat_main_per_thread_data_t *tsm;
501   per_vrf_sessions_t *per_vrf_sessions;
502
503   ASSERT (s->per_vrf_sessions_index != ~0);
504
505   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
506   per_vrf_sessions =
507     vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
508
509   ASSERT (per_vrf_sessions->ses_count != 0);
510
511   per_vrf_sessions->ses_count--;
512   s->per_vrf_sessions_index = ~0;
513 }
514
515 // fast path
516 static_always_inline u8
517 per_vrf_sessions_is_expired (snat_session_t *s, u32 thread_index)
518 {
519   snat_main_t *sm = &snat_main;
520   snat_main_per_thread_data_t *tsm;
521   per_vrf_sessions_t *per_vrf_sessions;
522
523   ASSERT (s->per_vrf_sessions_index != ~0);
524
525   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
526   per_vrf_sessions =
527     vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
528   return per_vrf_sessions->expired;
529 }
530
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)
535 {
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;
543 }
544
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)
549 {
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);
554 }
555
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)
560 {
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);
565 }
566
567 static_always_inline int
568 nat_6t_t_eq (nat_6t_t *t1, nat_6t_t *t2)
569 {
570   return t1->as_u64[0] == t2->as_u64[0] && t1->as_u64[1] == t2->as_u64[1];
571 }
572
573 static inline uword
574 nat_pre_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
575                         vlib_frame_t *frame, u32 def_next)
576 {
577   u32 n_left_from, *from;
578
579   from = vlib_frame_vector_args (frame);
580   n_left_from = frame->n_vectors;
581
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);
585
586   while (n_left_from >= 2)
587     {
588       u32 next0, next1;
589       u32 arc_next0, arc_next1;
590       vlib_buffer_t *b0, *b1;
591
592       b0 = *b;
593       b++;
594       b1 = *b;
595       b++;
596
597       /* Prefetch next iteration. */
598       if (PREDICT_TRUE (n_left_from >= 4))
599         {
600           vlib_buffer_t *p2, *p3;
601
602           p2 = *b;
603           p3 = *(b + 1);
604
605           vlib_prefetch_buffer_header (p2, LOAD);
606           vlib_prefetch_buffer_header (p3, LOAD);
607
608           clib_prefetch_load (p2->data);
609           clib_prefetch_load (p3->data);
610         }
611
612       next0 = def_next;
613       next1 = def_next;
614
615       vnet_feature_next (&arc_next0, b0);
616       vnet_feature_next (&arc_next1, b1);
617
618       vnet_buffer2 (b0)->nat.arc_next = arc_next0;
619       vnet_buffer2 (b1)->nat.arc_next = arc_next1;
620
621       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
622         {
623           if (b0->flags & VLIB_BUFFER_IS_TRACED)
624             {
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;
628             }
629           if (b1->flags & VLIB_BUFFER_IS_TRACED)
630             {
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;
634             }
635         }
636
637       n_left_from -= 2;
638       next[0] = next0;
639       next[1] = next1;
640       next += 2;
641     }
642
643   while (n_left_from > 0)
644     {
645       u32 next0;
646       u32 arc_next0;
647       vlib_buffer_t *b0;
648
649       b0 = *b;
650       b++;
651
652       next0 = def_next;
653       vnet_feature_next (&arc_next0, b0);
654       vnet_buffer2 (b0)->nat.arc_next = arc_next0;
655
656       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
657                          (b0->flags & VLIB_BUFFER_IS_TRACED)))
658         {
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;
662         }
663
664       n_left_from--;
665       next[0] = next0;
666       next++;
667     }
668   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
669                                frame->n_vectors);
670
671   return frame->n_vectors;
672 }
673
674 static_always_inline u16
675 snat_random_port (u16 min, u16 max)
676 {
677   snat_main_t *sm = &snat_main;
678   u32 rwide;
679   u16 r;
680
681   rwide = random_u32 (&sm->random_seed);
682   r = rwide & 0xFFFF;
683   if (r >= min && r <= max)
684     return r;
685
686   return min + (rwide % (max - min + 1));
687 }
688
689 always_inline u8
690 is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node,
691                    u32 sw_if_index0, u32 ip4_addr)
692 {
693   snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
694   u8 ip4_addr_exists;
695
696   if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
697     {
698       ip_lookup_main_t *lm = &sm->ip4_main->lookup_main;
699       ip_interface_address_t *ia;
700       ip4_address_t *a;
701
702       rt->cached_sw_if_index = ~0;
703       hash_free (rt->cached_presence_by_ip4_address);
704
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;
710         }));
711
712       if (rt->cached_sw_if_index == ~0)
713         return 0;
714     }
715
716   ip4_addr_exists = !!hash_get (rt->cached_presence_by_ip4_address, ip4_addr);
717   if (PREDICT_FALSE (ip4_addr_exists))
718     return 1;
719   else
720     return 0;
721 }
722
723 always_inline void
724 nat44_ed_session_reopen (u32 thread_index, snat_session_t *s)
725 {
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));
731
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);
738
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);
743   s->total_pkts = 0;
744   s->total_bytes = 0;
745 }
746
747 always_inline void
748 nat44_ed_init_tcp_state_stable (snat_main_t *sm)
749 {
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)
754     {
755       int i;
756       for (i = 0; i < NAT44_ED_N_DIR; ++i)
757         {
758           int j = 0;
759           for (j = 0; j < NAT44_ED_TCP_N_FLAG; ++j)
760             {
761               sm->tcp_state_change_table[s][i][j] = s;
762             }
763         }
764     }
765
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;
785
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;
805
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;
831
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;
845
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;
871
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;
897
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;
923
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;
949 }
950
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. */
955 always_inline void
956 nat44_set_tcp_session_state (snat_main_t *sm, f64 now, snat_session_t *ses,
957                              u8 tcp_flags, u32 thread_index,
958                              nat44_ed_dir_e dir)
959 {
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);
963
964   u8 old_state = ses->tcp_state;
965   ses->tcp_state = sm->tcp_state_change_table[ses->tcp_state][dir][flags];
966
967   if (old_state != ses->tcp_state)
968     {
969       if (nat44_ed_tcp_is_established (ses->tcp_state))
970         {
971           if (NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O == old_state ||
972               NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I == old_state)
973             {
974               nat44_ed_session_reopen (thread_index, ses);
975             }
976           ses->lru_head_index = tsm->tcp_estab_lru_head_index;
977         }
978       else
979         {
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;
985             }
986           ses->lru_head_index = tsm->tcp_trans_lru_head_index;
987         }
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);
991     }
992 }
993
994 always_inline void
995 nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses,
996                                  u8 tcp_flags, u32 thread_index)
997 {
998   return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
999                                       NAT44_ED_DIR_I2O);
1000 }
1001
1002 always_inline void
1003 nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses,
1004                                  u8 tcp_flags, u32 thread_index)
1005 {
1006   return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
1007                                       NAT44_ED_DIR_O2I);
1008 }
1009
1010 always_inline void
1011 nat44_session_update_counters (snat_session_t *s, f64 now, uword bytes,
1012                                u32 thread_index)
1013 {
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)
1018     {
1019       s->last_heard = now;
1020     }
1021   s->total_pkts++;
1022   s->total_bytes += bytes;
1023 }
1024
1025 /** \brief Per-user LRU list maintenance */
1026 always_inline void
1027 nat44_session_update_lru (snat_main_t *sm, snat_session_t *s, u32 thread_index)
1028 {
1029   /* don't update too often - timeout is in magnitude of seconds anyway */
1030   if (s->last_heard > s->last_lru_update + 1)
1031     {
1032       clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
1033                          s->lru_index);
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;
1037     }
1038 }
1039
1040 static_always_inline int
1041 nat44_ed_is_unk_proto (u8 proto)
1042 {
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,
1048   };
1049
1050   return 1 - lookup_table[proto];
1051 }
1052
1053 #endif /* __included_nat44_ed_inlines_h__ */
1054
1055 /*
1056  * fd.io coding-style-patch-verification: ON
1057  *
1058  * Local Variables:
1059  * eval: (c-set-style "gnu")
1060  * End:
1061  */