nat: nat44-ed cleanup & fixes
[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 /**
17  * @brief The NAT inline functions
18  */
19
20 #ifndef __included_nat44_ed_inlines_h__
21 #define __included_nat44_ed_inlines_h__
22
23 #include <float.h>
24 #include <vppinfra/clib.h>
25 #include <vnet/fib/ip4_fib.h>
26
27 #include <nat/lib/log.h>
28 #include <nat/lib/ipfix_logging.h>
29 #include <nat/nat44-ed/nat44_ed.h>
30
31 always_inline void
32 init_ed_k (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr,
33            u16 r_port, u32 fib_index, ip_protocol_t proto)
34 {
35   kv->key[0] = (u64) r_addr << 32 | l_addr;
36   kv->key[1] =
37     (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
38 }
39
40 always_inline void
41 init_ed_kv (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr,
42             u16 r_port, u32 fib_index, u8 proto, u32 thread_index,
43             u32 session_index)
44 {
45   init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto);
46   kv->value = (u64) thread_index << 32 | session_index;
47 }
48
49 always_inline void
50 nat44_ed_sm_init_i2o_kv (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port,
51                          u32 fib_index, u8 proto, u32 sm_index)
52 {
53   return init_ed_kv (kv, addr, port, 0, 0, fib_index, proto, 0, sm_index);
54 }
55
56 always_inline void
57 nat44_ed_sm_init_o2i_kv (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port,
58                          u32 fib_index, u8 proto, u32 sm_index)
59 {
60   return init_ed_kv (kv, 0, 0, e_addr, e_port, fib_index, proto, 0, sm_index);
61 }
62
63 always_inline void
64 nat44_ed_sm_init_i2o_k (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port,
65                         u32 fib_index, u8 proto)
66 {
67   return nat44_ed_sm_init_i2o_kv (kv, addr, port, fib_index, proto, 0);
68 }
69
70 always_inline void
71 nat44_ed_sm_init_o2i_k (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port,
72                         u32 fib_index, u8 proto)
73 {
74   return nat44_ed_sm_init_o2i_kv (kv, e_addr, e_port, fib_index, proto, 0);
75 }
76
77 always_inline u32
78 ed_value_get_thread_index (clib_bihash_kv_16_8_t *value)
79 {
80   return value->value >> 32;
81 }
82
83 always_inline u32
84 ed_value_get_session_index (clib_bihash_kv_16_8_t *value)
85 {
86   return value->value & ~(u32) 0;
87 }
88
89 always_inline void
90 split_ed_kv (clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr,
91              ip4_address_t *r_addr, u8 *proto, u32 *fib_index, u16 *l_port,
92              u16 *r_port)
93 {
94   if (l_addr)
95     {
96       l_addr->as_u32 = kv->key[0] & (u32) ~0;
97     }
98   if (r_addr)
99     {
100       r_addr->as_u32 = kv->key[0] >> 32;
101     }
102   if (r_port)
103     {
104       *r_port = kv->key[1] >> 48;
105     }
106   if (l_port)
107     {
108       *l_port = (kv->key[1] >> 32) & (u16) ~0;
109     }
110   if (fib_index)
111     {
112       *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
113     }
114   if (proto)
115     {
116       *proto = kv->key[1] & (u8) ~0;
117     }
118 }
119
120 static_always_inline int
121 nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0,
122                                     ip4_address_t *lookup_saddr,
123                                     u16 *lookup_sport,
124                                     ip4_address_t *lookup_daddr,
125                                     u16 *lookup_dport, u8 *lookup_protocol)
126 {
127   icmp46_header_t *icmp0;
128   nat_icmp_echo_header_t *echo0, *inner_echo0 = 0;
129   ip4_header_t *inner_ip0 = 0;
130   void *l4_header = 0;
131   icmp46_header_t *inner_icmp0;
132
133   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
134   echo0 = (nat_icmp_echo_header_t *) (icmp0 + 1);
135
136   // avoid warning about unused variables in caller by setting to bogus values
137   *lookup_sport = 0;
138   *lookup_dport = 0;
139
140   if (!icmp_type_is_error_message (
141         vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
142     {
143       *lookup_protocol = IP_PROTOCOL_ICMP;
144       lookup_saddr->as_u32 = ip0->src_address.as_u32;
145       *lookup_sport = vnet_buffer (b)->ip.reass.l4_src_port;
146       lookup_daddr->as_u32 = ip0->dst_address.as_u32;
147       *lookup_dport = vnet_buffer (b)->ip.reass.l4_dst_port;
148     }
149   else
150     {
151       inner_ip0 = (ip4_header_t *) (echo0 + 1);
152       l4_header = ip4_next_header (inner_ip0);
153       *lookup_protocol = inner_ip0->protocol;
154       lookup_saddr->as_u32 = inner_ip0->dst_address.as_u32;
155       lookup_daddr->as_u32 = inner_ip0->src_address.as_u32;
156       switch (inner_ip0->protocol)
157         {
158         case IP_PROTOCOL_ICMP:
159           inner_icmp0 = (icmp46_header_t *) l4_header;
160           inner_echo0 = (nat_icmp_echo_header_t *) (inner_icmp0 + 1);
161           *lookup_sport = inner_echo0->identifier;
162           *lookup_dport = inner_echo0->identifier;
163           break;
164         case IP_PROTOCOL_UDP:
165         case IP_PROTOCOL_TCP:
166           *lookup_sport = ((nat_tcp_udp_header_t *) l4_header)->dst_port;
167           *lookup_dport = ((nat_tcp_udp_header_t *) l4_header)->src_port;
168           break;
169         default:
170           return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
171         }
172     }
173   return 0;
174 }
175
176 always_inline int
177 nat44_ed_tcp_is_established (nat44_ed_tcp_state_e state)
178 {
179   static int lookup[] = {
180     [NAT44_ED_TCP_STATE_CLOSED] = 0,
181     [NAT44_ED_TCP_STATE_SYN_I2O] = 0,
182     [NAT44_ED_TCP_STATE_SYN_O2I] = 0,
183     [NAT44_ED_TCP_STATE_ESTABLISHED] = 1,
184     [NAT44_ED_TCP_STATE_FIN_I2O] = 1,
185     [NAT44_ED_TCP_STATE_FIN_O2I] = 1,
186     [NAT44_ED_TCP_STATE_RST_TRANS] = 0,
187     [NAT44_ED_TCP_STATE_FIN_TRANS] = 0,
188     [NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O] = 0,
189     [NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I] = 0,
190     [NAT44_ED_TCP_N_STATE] = 0,
191   };
192   ASSERT (state <= ARRAY_LEN (lookup));
193   return lookup[state];
194 }
195
196 always_inline u32
197 nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s)
198 {
199   switch (s->proto)
200     {
201     case IP_PROTOCOL_ICMP:
202       /* fallthrough */
203     case IP_PROTOCOL_ICMP6:
204       return sm->timeouts.icmp;
205     case IP_PROTOCOL_UDP:
206       return sm->timeouts.udp;
207     case IP_PROTOCOL_TCP:
208       {
209         if (nat44_ed_tcp_is_established (s->tcp_state))
210           return sm->timeouts.tcp.established;
211         else
212           return sm->timeouts.tcp.transitory;
213       }
214     default:
215       return sm->timeouts.udp;
216     }
217
218   return 0;
219 }
220
221 static_always_inline u8
222 nat44_ed_maximum_sessions_exceeded (snat_main_t *sm, u32 fib_index,
223                                     u32 thread_index)
224 {
225   u32 translations;
226   translations = pool_elts (sm->per_thread_data[thread_index].sessions);
227   if (vec_len (sm->max_translations_per_fib) <= fib_index)
228     fib_index = 0;
229   return translations >= sm->max_translations_per_fib[fib_index];
230 }
231
232 static_always_inline int
233 nat_ed_lru_insert (snat_main_per_thread_data_t *tsm, snat_session_t *s,
234                    f64 now, u8 proto)
235 {
236   dlist_elt_t *lru_list_elt;
237   pool_get (tsm->lru_pool, lru_list_elt);
238   s->lru_index = lru_list_elt - tsm->lru_pool;
239   switch (proto)
240     {
241     case IP_PROTOCOL_UDP:
242       s->lru_head_index = tsm->udp_lru_head_index;
243       break;
244     case IP_PROTOCOL_TCP:
245       s->lru_head_index = tsm->tcp_trans_lru_head_index;
246       break;
247     case IP_PROTOCOL_ICMP:
248       s->lru_head_index = tsm->icmp_lru_head_index;
249       break;
250     default:
251       s->lru_head_index = tsm->unk_proto_lru_head_index;
252       break;
253     }
254   clib_dlist_addtail (tsm->lru_pool, s->lru_head_index, s->lru_index);
255   lru_list_elt->value = s - tsm->sessions;
256   s->last_lru_update = now;
257   return 1;
258 }
259
260 static_always_inline void
261 nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
262 {
263   init_ed_k (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32,
264              f->match.dport, f->match.fib_index, f->match.proto);
265 }
266
267 static_always_inline void
268 nat_6t_flow_to_ed_kv (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f,
269                       u32 thread_idx, u32 session_idx)
270 {
271   init_ed_kv (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32,
272               f->match.dport, f->match.fib_index, f->match.proto, thread_idx,
273               session_idx);
274 }
275
276 static_always_inline int
277 nat_ed_ses_i2o_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
278                                   snat_session_t *s, int is_add)
279 {
280   snat_main_per_thread_data_t *tsm =
281     vec_elt_at_index (sm->per_thread_data, thread_idx);
282   clib_bihash_kv_16_8_t kv;
283   if (0 == is_add)
284     {
285       nat_6t_flow_to_ed_k (&kv, &s->i2o);
286     }
287   else
288     {
289       nat_6t_flow_to_ed_kv (&kv, &s->i2o, thread_idx, s - tsm->sessions);
290       nat_6t_l3_l4_csum_calc (&s->i2o);
291     }
292
293   ASSERT (thread_idx == s->thread_index);
294   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
295 }
296
297 static_always_inline int
298 nat_ed_ses_o2i_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
299                                   snat_session_t *s, int is_add)
300 {
301   snat_main_per_thread_data_t *tsm =
302     vec_elt_at_index (sm->per_thread_data, thread_idx);
303   clib_bihash_kv_16_8_t kv;
304   if (0 == is_add)
305     {
306       nat_6t_flow_to_ed_k (&kv, &s->o2i);
307     }
308   else
309     {
310       nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions);
311       if (!(s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
312         {
313           if (nat44_ed_sm_o2i_lookup (sm, s->o2i.match.daddr,
314                                       s->o2i.match.dport, 0,
315                                       s->o2i.match.proto))
316             {
317               return -1;
318             }
319         }
320       nat_6t_l3_l4_csum_calc (&s->o2i);
321     }
322   ASSERT (thread_idx == s->thread_index);
323   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
324 }
325
326 always_inline void
327 nat_ed_session_delete (snat_main_t *sm, snat_session_t *ses, u32 thread_index,
328                        int lru_delete
329                        /* delete from global LRU list */)
330 {
331   snat_main_per_thread_data_t *tsm =
332     vec_elt_at_index (sm->per_thread_data, thread_index);
333
334   if (lru_delete)
335     {
336       clib_dlist_remove (tsm->lru_pool, ses->lru_index);
337     }
338   pool_put_index (tsm->lru_pool, ses->lru_index);
339   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, ses, 0))
340     nat_elog_warn (sm, "flow hash del failed");
341   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, ses, 0))
342     nat_elog_warn (sm, "flow hash del failed");
343   pool_put (tsm->sessions, ses);
344   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
345                            pool_elts (tsm->sessions));
346 }
347
348 static_always_inline int
349 nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now,
350                             u32 head_index)
351 {
352   snat_session_t *s = NULL;
353   dlist_elt_t *oldest_elt;
354   f64 sess_timeout_time;
355   u32 oldest_index;
356   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
357   oldest_index = clib_dlist_remove_head (tsm->lru_pool, head_index);
358   if (~0 != oldest_index)
359     {
360       oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
361       s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
362
363       sess_timeout_time =
364         s->last_heard + (f64) nat44_session_get_timeout (sm, s);
365       if (now >= sess_timeout_time)
366         {
367           nat44_ed_free_session_data (sm, s, thread_index, 0);
368           nat_ed_session_delete (sm, s, thread_index, 0);
369           return 1;
370         }
371       else
372         {
373           clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
374         }
375     }
376   return 0;
377 }
378
379 static_always_inline int
380 nat_lru_free_one (snat_main_t *sm, int thread_index, f64 now)
381 {
382   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
383   int rc = 0;
384 #define _(p)                                                                  \
385   if ((rc = nat_lru_free_one_with_head (sm, thread_index, now,                \
386                                         tsm->p##_lru_head_index)))            \
387     {                                                                         \
388       return rc;                                                              \
389     }
390   _ (tcp_trans);
391   _ (udp);
392   _ (unk_proto);
393   _ (icmp);
394   _ (tcp_estab);
395 #undef _
396   return 0;
397 }
398
399 static_always_inline snat_session_t *
400 nat_ed_session_alloc (snat_main_t *sm, u32 thread_index, f64 now, u8 proto)
401 {
402   snat_session_t *s;
403   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
404
405   nat_lru_free_one (sm, thread_index, now);
406
407   pool_get (tsm->sessions, s);
408   clib_memset (s, 0, sizeof (*s));
409
410   nat_ed_lru_insert (tsm, s, now, proto);
411
412   s->ha_last_refreshed = now;
413   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
414                            pool_elts (tsm->sessions));
415 #if CLIB_ASSERT_ENABLE
416   s->thread_index = thread_index;
417 #endif
418   return s;
419 }
420
421 // slow path
422 static_always_inline void
423 per_vrf_sessions_cleanup (u32 thread_index)
424 {
425   snat_main_t *sm = &snat_main;
426   snat_main_per_thread_data_t *tsm =
427     vec_elt_at_index (sm->per_thread_data, thread_index);
428   per_vrf_sessions_t *per_vrf_sessions;
429   u32 *to_free = 0, *i;
430
431   vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
432     {
433       if (per_vrf_sessions->expired)
434         {
435           if (per_vrf_sessions->ses_count == 0)
436             {
437               vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_vec);
438             }
439         }
440     }
441
442   if (vec_len (to_free))
443     {
444       vec_foreach (i, to_free)
445         {
446           vec_del1 (tsm->per_vrf_sessions_vec, *i);
447         }
448     }
449
450   vec_free (to_free);
451 }
452
453 // slow path
454 static_always_inline void
455 per_vrf_sessions_register_session (snat_session_t *s, u32 thread_index)
456 {
457   snat_main_t *sm = &snat_main;
458   snat_main_per_thread_data_t *tsm =
459     vec_elt_at_index (sm->per_thread_data, thread_index);
460   per_vrf_sessions_t *per_vrf_sessions;
461
462   per_vrf_sessions_cleanup (thread_index);
463
464   // s->per_vrf_sessions_index == ~0 ... reuse of old session
465
466   vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
467     {
468       // ignore already expired registrations
469       if (per_vrf_sessions->expired)
470         continue;
471
472       if ((s->in2out.fib_index == per_vrf_sessions->rx_fib_index) &&
473           (s->out2in.fib_index == per_vrf_sessions->tx_fib_index))
474         {
475           goto done;
476         }
477       if ((s->in2out.fib_index == per_vrf_sessions->tx_fib_index) &&
478           (s->out2in.fib_index == per_vrf_sessions->rx_fib_index))
479         {
480           goto done;
481         }
482     }
483
484   // create a new registration
485   vec_add2 (tsm->per_vrf_sessions_vec, per_vrf_sessions, 1);
486   clib_memset (per_vrf_sessions, 0, sizeof (*per_vrf_sessions));
487
488   per_vrf_sessions->rx_fib_index = s->in2out.fib_index;
489   per_vrf_sessions->tx_fib_index = s->out2in.fib_index;
490
491 done:
492   s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_vec;
493   per_vrf_sessions->ses_count++;
494 }
495
496 // fast path
497 static_always_inline void
498 per_vrf_sessions_unregister_session (snat_session_t *s, u32 thread_index)
499 {
500   snat_main_t *sm = &snat_main;
501   snat_main_per_thread_data_t *tsm;
502   per_vrf_sessions_t *per_vrf_sessions;
503
504   ASSERT (s->per_vrf_sessions_index != ~0);
505
506   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
507   per_vrf_sessions =
508     vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
509
510   ASSERT (per_vrf_sessions->ses_count != 0);
511
512   per_vrf_sessions->ses_count--;
513   s->per_vrf_sessions_index = ~0;
514 }
515
516 // fast path
517 static_always_inline u8
518 per_vrf_sessions_is_expired (snat_session_t *s, u32 thread_index)
519 {
520   snat_main_t *sm = &snat_main;
521   snat_main_per_thread_data_t *tsm;
522   per_vrf_sessions_t *per_vrf_sessions;
523
524   ASSERT (s->per_vrf_sessions_index != ~0);
525
526   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
527   per_vrf_sessions =
528     vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
529   return per_vrf_sessions->expired;
530 }
531
532 static_always_inline void
533 nat_6t_flow_init (nat_6t_flow_t *f, u32 thread_idx, ip4_address_t saddr,
534                   u16 sport, ip4_address_t daddr, u16 dport, u32 fib_index,
535                   u8 proto, u32 session_idx)
536 {
537   clib_memset (f, 0, sizeof (*f));
538   f->match.saddr = saddr;
539   f->match.sport = sport;
540   f->match.daddr = daddr;
541   f->match.dport = dport;
542   f->match.proto = proto;
543   f->match.fib_index = fib_index;
544 }
545
546 static_always_inline void
547 nat_6t_i2o_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
548                       ip4_address_t saddr, u16 sport, ip4_address_t daddr,
549                       u16 dport, u32 fib_index, u8 proto)
550 {
551   snat_main_per_thread_data_t *tsm =
552     vec_elt_at_index (sm->per_thread_data, thread_idx);
553   nat_6t_flow_init (&s->i2o, thread_idx, saddr, sport, daddr, dport, fib_index,
554                     proto, s - tsm->sessions);
555 }
556
557 static_always_inline void
558 nat_6t_o2i_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
559                       ip4_address_t saddr, u16 sport, ip4_address_t daddr,
560                       u16 dport, u32 fib_index, u8 proto)
561 {
562   snat_main_per_thread_data_t *tsm =
563     vec_elt_at_index (sm->per_thread_data, thread_idx);
564   nat_6t_flow_init (&s->o2i, thread_idx, saddr, sport, daddr, dport, fib_index,
565                     proto, s - tsm->sessions);
566 }
567
568 static_always_inline int
569 nat_6t_t_eq (nat_6t_t *t1, nat_6t_t *t2)
570 {
571   return t1->as_u64[0] == t2->as_u64[0] && t1->as_u64[1] == t2->as_u64[1];
572 }
573
574 static inline uword
575 nat_pre_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
576                         vlib_frame_t *frame, u32 def_next)
577 {
578   u32 n_left_from, *from;
579
580   from = vlib_frame_vector_args (frame);
581   n_left_from = frame->n_vectors;
582
583   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
584   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
585   vlib_get_buffers (vm, from, b, n_left_from);
586
587   while (n_left_from >= 2)
588     {
589       u32 next0, next1;
590       u32 arc_next0, arc_next1;
591       vlib_buffer_t *b0, *b1;
592
593       b0 = *b;
594       b++;
595       b1 = *b;
596       b++;
597
598       /* Prefetch next iteration. */
599       if (PREDICT_TRUE (n_left_from >= 4))
600         {
601           vlib_buffer_t *p2, *p3;
602
603           p2 = *b;
604           p3 = *(b + 1);
605
606           vlib_prefetch_buffer_header (p2, LOAD);
607           vlib_prefetch_buffer_header (p3, LOAD);
608
609           clib_prefetch_load (p2->data);
610           clib_prefetch_load (p3->data);
611         }
612
613       next0 = def_next;
614       next1 = def_next;
615
616       vnet_feature_next (&arc_next0, b0);
617       vnet_feature_next (&arc_next1, b1);
618
619       vnet_buffer2 (b0)->nat.arc_next = arc_next0;
620       vnet_buffer2 (b1)->nat.arc_next = arc_next1;
621
622       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
623         {
624           if (b0->flags & VLIB_BUFFER_IS_TRACED)
625             {
626               nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
627               t->next_index = next0;
628               t->arc_next_index = arc_next0;
629             }
630           if (b1->flags & VLIB_BUFFER_IS_TRACED)
631             {
632               nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
633               t->next_index = next1;
634               t->arc_next_index = arc_next1;
635             }
636         }
637
638       n_left_from -= 2;
639       next[0] = next0;
640       next[1] = next1;
641       next += 2;
642     }
643
644   while (n_left_from > 0)
645     {
646       u32 next0;
647       u32 arc_next0;
648       vlib_buffer_t *b0;
649
650       b0 = *b;
651       b++;
652
653       next0 = def_next;
654       vnet_feature_next (&arc_next0, b0);
655       vnet_buffer2 (b0)->nat.arc_next = arc_next0;
656
657       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
658                          (b0->flags & VLIB_BUFFER_IS_TRACED)))
659         {
660           nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
661           t->next_index = next0;
662           t->arc_next_index = arc_next0;
663         }
664
665       n_left_from--;
666       next[0] = next0;
667       next++;
668     }
669   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
670                                frame->n_vectors);
671
672   return frame->n_vectors;
673 }
674
675 static_always_inline u16
676 snat_random_port (u16 min, u16 max)
677 {
678   snat_main_t *sm = &snat_main;
679   u32 rwide;
680   u16 r;
681
682   rwide = random_u32 (&sm->random_seed);
683   r = rwide & 0xFFFF;
684   if (r >= min && r <= max)
685     return r;
686
687   return min + (rwide % (max - min + 1));
688 }
689
690 always_inline u8
691 is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node,
692                    u32 sw_if_index0, u32 ip4_addr)
693 {
694   snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
695   u8 ip4_addr_exists;
696
697   if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
698     {
699       ip_lookup_main_t *lm = &sm->ip4_main->lookup_main;
700       ip_interface_address_t *ia;
701       ip4_address_t *a;
702
703       rt->cached_sw_if_index = ~0;
704       hash_free (rt->cached_presence_by_ip4_address);
705
706       foreach_ip_interface_address (
707         lm, ia, sw_if_index0, 1 /* honor unnumbered */, ({
708           a = ip_interface_address_get_address (lm, ia);
709           hash_set (rt->cached_presence_by_ip4_address, a->as_u32, 1);
710           rt->cached_sw_if_index = sw_if_index0;
711         }));
712
713       if (rt->cached_sw_if_index == ~0)
714         return 0;
715     }
716
717   ip4_addr_exists = !!hash_get (rt->cached_presence_by_ip4_address, ip4_addr);
718   if (PREDICT_FALSE (ip4_addr_exists))
719     return 1;
720   else
721     return 0;
722 }
723
724 always_inline void
725 nat44_ed_session_reopen (u32 thread_index, snat_session_t *s)
726 {
727   nat_syslog_nat44_sdel (0, s->in2out.fib_index, &s->in2out.addr,
728                          s->in2out.port, &s->ext_host_nat_addr,
729                          s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
730                          &s->ext_host_addr, s->ext_host_port, s->proto,
731                          nat44_ed_is_twice_nat_session (s));
732
733   nat_ipfix_logging_nat44_ses_delete (
734     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
735     s->in2out.port, s->out2in.port, s->in2out.fib_index);
736   nat_ipfix_logging_nat44_ses_create (
737     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
738     s->in2out.port, s->out2in.port, s->in2out.fib_index);
739
740   nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
741                          s->in2out.port, &s->ext_host_nat_addr,
742                          s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
743                          &s->ext_host_addr, s->ext_host_port, s->proto, 0);
744   s->total_pkts = 0;
745   s->total_bytes = 0;
746 }
747
748 always_inline void
749 nat44_ed_init_tcp_state_stable (snat_main_t *sm)
750 {
751   /* first make sure whole table is initialised in a way where state
752    * is not changed, then define special cases */
753   nat44_ed_tcp_state_e s;
754   for (s = 0; s < NAT44_ED_TCP_N_STATE; ++s)
755     {
756       int i;
757       for (i = 0; i < NAT44_ED_N_DIR; ++i)
758         {
759           int j = 0;
760           for (j = 0; j < NAT44_ED_TCP_N_FLAG; ++j)
761             {
762               sm->tcp_state_change_table[s][i][j] = s;
763             }
764         }
765     }
766
767   /* CLOSED and any kind of SYN -> HALF-OPEN */
768   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
769                             [NAT44_ED_TCP_FLAG_SYN] =
770     NAT44_ED_TCP_STATE_SYN_I2O;
771   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
772                             [NAT44_ED_TCP_FLAG_SYN] =
773     NAT44_ED_TCP_STATE_SYN_O2I;
774   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
775                             [NAT44_ED_TCP_FLAG_SYNFIN] =
776     NAT44_ED_TCP_STATE_SYN_I2O;
777   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
778                             [NAT44_ED_TCP_FLAG_SYNFIN] =
779     NAT44_ED_TCP_STATE_SYN_O2I;
780   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
781                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
782     NAT44_ED_TCP_STATE_SYN_I2O;
783   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
784                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
785     NAT44_ED_TCP_STATE_SYN_O2I;
786
787   /* HALF-OPEN and any kind of SYN in right direction -> ESTABLISHED */
788   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
789                             [NAT44_ED_TCP_FLAG_SYN] =
790     NAT44_ED_TCP_STATE_ESTABLISHED;
791   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
792                             [NAT44_ED_TCP_FLAG_SYN] =
793     NAT44_ED_TCP_STATE_ESTABLISHED;
794   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
795                             [NAT44_ED_TCP_FLAG_SYNFIN] =
796     NAT44_ED_TCP_STATE_ESTABLISHED;
797   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
798                             [NAT44_ED_TCP_FLAG_SYNFIN] =
799     NAT44_ED_TCP_STATE_ESTABLISHED;
800   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
801                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
802     NAT44_ED_TCP_STATE_ESTABLISHED;
803   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
804                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
805     NAT44_ED_TCP_STATE_ESTABLISHED;
806
807   /* ESTABLISHED and any kind of RST -> RST_TRANS */
808   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
809                             [NAT44_ED_TCP_FLAG_RST] =
810     NAT44_ED_TCP_STATE_RST_TRANS;
811   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
812                             [NAT44_ED_TCP_FLAG_RST] =
813     NAT44_ED_TCP_STATE_RST_TRANS;
814   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
815                             [NAT44_ED_TCP_FLAG_SYNRST] =
816     NAT44_ED_TCP_STATE_RST_TRANS;
817   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
818                             [NAT44_ED_TCP_FLAG_SYNRST] =
819     NAT44_ED_TCP_STATE_RST_TRANS;
820   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
821                             [NAT44_ED_TCP_FLAG_FINRST] =
822     NAT44_ED_TCP_STATE_RST_TRANS;
823   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
824                             [NAT44_ED_TCP_FLAG_FINRST] =
825     NAT44_ED_TCP_STATE_RST_TRANS;
826   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
827                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
828     NAT44_ED_TCP_STATE_RST_TRANS;
829   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
830                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
831     NAT44_ED_TCP_STATE_RST_TRANS;
832
833   /* ESTABLISHED and any kind of FIN without RST -> HALF-CLOSED */
834   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
835                             [NAT44_ED_TCP_FLAG_FIN] =
836     NAT44_ED_TCP_STATE_FIN_I2O;
837   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
838                             [NAT44_ED_TCP_FLAG_FIN] =
839     NAT44_ED_TCP_STATE_FIN_O2I;
840   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
841                             [NAT44_ED_TCP_FLAG_SYNFIN] =
842     NAT44_ED_TCP_STATE_FIN_I2O;
843   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
844                             [NAT44_ED_TCP_FLAG_SYNFIN] =
845     NAT44_ED_TCP_STATE_FIN_O2I;
846
847   /* HALF-CLOSED and any kind of FIN -> FIN_TRANS */
848   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
849                             [NAT44_ED_TCP_FLAG_FIN] =
850     NAT44_ED_TCP_STATE_FIN_TRANS;
851   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
852                             [NAT44_ED_TCP_FLAG_FIN] =
853     NAT44_ED_TCP_STATE_FIN_TRANS;
854   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
855                             [NAT44_ED_TCP_FLAG_SYNFIN] =
856     NAT44_ED_TCP_STATE_FIN_TRANS;
857   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
858                             [NAT44_ED_TCP_FLAG_SYNFIN] =
859     NAT44_ED_TCP_STATE_FIN_TRANS;
860   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
861                             [NAT44_ED_TCP_FLAG_FINRST] =
862     NAT44_ED_TCP_STATE_FIN_TRANS;
863   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
864                             [NAT44_ED_TCP_FLAG_FINRST] =
865     NAT44_ED_TCP_STATE_FIN_TRANS;
866   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
867                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
868     NAT44_ED_TCP_STATE_FIN_TRANS;
869   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
870                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
871     NAT44_ED_TCP_STATE_FIN_TRANS;
872
873   /* RST_TRANS and anything non-RST -> ESTABLISHED */
874   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
875                             [NAT44_ED_TCP_FLAG_NONE] =
876     NAT44_ED_TCP_STATE_ESTABLISHED;
877   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
878                             [NAT44_ED_TCP_FLAG_NONE] =
879     NAT44_ED_TCP_STATE_ESTABLISHED;
880   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
881                             [NAT44_ED_TCP_FLAG_SYN] =
882     NAT44_ED_TCP_STATE_ESTABLISHED;
883   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
884                             [NAT44_ED_TCP_FLAG_SYN] =
885     NAT44_ED_TCP_STATE_ESTABLISHED;
886   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
887                             [NAT44_ED_TCP_FLAG_FIN] =
888     NAT44_ED_TCP_STATE_ESTABLISHED;
889   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
890                             [NAT44_ED_TCP_FLAG_FIN] =
891     NAT44_ED_TCP_STATE_ESTABLISHED;
892   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
893                             [NAT44_ED_TCP_FLAG_SYNFIN] =
894     NAT44_ED_TCP_STATE_ESTABLISHED;
895   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
896                             [NAT44_ED_TCP_FLAG_SYNFIN] =
897     NAT44_ED_TCP_STATE_ESTABLISHED;
898
899   /* FIN_TRANS and any kind of SYN -> HALF-REOPEN */
900   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
901                             [NAT44_ED_TCP_FLAG_SYN] =
902     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
903   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
904                             [NAT44_ED_TCP_FLAG_SYN] =
905     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
906   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
907                             [NAT44_ED_TCP_FLAG_SYNRST] =
908     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
909   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
910                             [NAT44_ED_TCP_FLAG_SYNRST] =
911     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
912   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
913                             [NAT44_ED_TCP_FLAG_SYNFIN] =
914     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
915   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
916                             [NAT44_ED_TCP_FLAG_SYNFIN] =
917     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
918   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
919                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
920     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
921   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
922                             [NAT44_ED_TCP_FLAG_SYNFINRST] =
923     NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
924
925   /* HALF-REOPEN and any kind of SYN in right direction -> ESTABLISHED */
926   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
927                             [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYN] =
928     NAT44_ED_TCP_STATE_ESTABLISHED;
929   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
930                             [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYN] =
931     NAT44_ED_TCP_STATE_ESTABLISHED;
932   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
933                             [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNRST] =
934     NAT44_ED_TCP_STATE_ESTABLISHED;
935   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
936                             [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNRST] =
937     NAT44_ED_TCP_STATE_ESTABLISHED;
938   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
939                             [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNFIN] =
940     NAT44_ED_TCP_STATE_ESTABLISHED;
941   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
942                             [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNFIN] =
943     NAT44_ED_TCP_STATE_ESTABLISHED;
944   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
945                             [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNFINRST] =
946     NAT44_ED_TCP_STATE_ESTABLISHED;
947   sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
948                             [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNFINRST] =
949     NAT44_ED_TCP_STATE_ESTABLISHED;
950 }
951
952 /* TCP state tracking according to RFC 7857 (and RFC 6146, which is referenced
953  * by RFC 7857). Our implementation also goes beyond by supporting creation of
954  * a new session while old session is in transitory timeout after seeing FIN
955  * packets from both sides. */
956 always_inline void
957 nat44_set_tcp_session_state (snat_main_t *sm, f64 now, snat_session_t *ses,
958                              u8 tcp_flags, u32 thread_index,
959                              nat44_ed_dir_e dir)
960 {
961   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
962   nat44_ed_tcp_flag_e flags =
963     tcp_flags & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST);
964
965   u8 old_state = ses->tcp_state;
966   ses->tcp_state = sm->tcp_state_change_table[ses->tcp_state][dir][flags];
967
968   if (old_state != ses->tcp_state)
969     {
970       if (nat44_ed_tcp_is_established (ses->tcp_state))
971         {
972           if (NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O == old_state ||
973               NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I == old_state)
974             {
975               nat44_ed_session_reopen (thread_index, ses);
976             }
977           ses->lru_head_index = tsm->tcp_estab_lru_head_index;
978         }
979       else
980         {
981           if (NAT44_ED_TCP_STATE_ESTABLISHED == old_state)
982             { // need to update last heard otherwise session might get
983               // immediately timed out if it has been idle longer than
984               // transitory timeout
985               ses->last_heard = now;
986             }
987           ses->lru_head_index = tsm->tcp_trans_lru_head_index;
988         }
989       ses->last_lru_update = now;
990       clib_dlist_remove (tsm->lru_pool, ses->lru_index);
991       clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
992     }
993 }
994
995 always_inline void
996 nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses,
997                                  u8 tcp_flags, u32 thread_index)
998 {
999   return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
1000                                       NAT44_ED_DIR_I2O);
1001 }
1002
1003 always_inline void
1004 nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses,
1005                                  u8 tcp_flags, u32 thread_index)
1006 {
1007   return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
1008                                       NAT44_ED_DIR_O2I);
1009 }
1010
1011 always_inline void
1012 nat44_session_update_counters (snat_session_t *s, f64 now, uword bytes,
1013                                u32 thread_index)
1014 {
1015   if (NAT44_ED_TCP_STATE_RST_TRANS != s->tcp_state &&
1016       NAT44_ED_TCP_STATE_FIN_TRANS != s->tcp_state &&
1017       NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O != s->tcp_state &&
1018       NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I != s->tcp_state)
1019     {
1020       s->last_heard = now;
1021     }
1022   s->total_pkts++;
1023   s->total_bytes += bytes;
1024 }
1025
1026 /** \brief Per-user LRU list maintenance */
1027 always_inline void
1028 nat44_session_update_lru (snat_main_t *sm, snat_session_t *s, u32 thread_index)
1029 {
1030   /* don't update too often - timeout is in magnitude of seconds anyway */
1031   if (s->last_heard > s->last_lru_update + 1)
1032     {
1033       clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
1034                          s->lru_index);
1035       clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool,
1036                           s->lru_head_index, s->lru_index);
1037       s->last_lru_update = s->last_heard;
1038     }
1039 }
1040
1041 static_always_inline int
1042 nat44_ed_is_unk_proto (u8 proto)
1043 {
1044   static const int lookup_table[256] = {
1045     [IP_PROTOCOL_TCP] = 1,
1046     [IP_PROTOCOL_UDP] = 1,
1047     [IP_PROTOCOL_ICMP] = 1,
1048     [IP_PROTOCOL_ICMP6] = 1,
1049   };
1050
1051   return 1 - lookup_table[proto];
1052 }
1053
1054 #endif /* __included_nat44_ed_inlines_h__ */
1055
1056 /*
1057  * fd.io coding-style-patch-verification: ON
1058  *
1059  * Local Variables:
1060  * eval: (c-set-style "gnu")
1061  * End:
1062  */