nat: remove unused code
[vpp.git] / src / plugins / nat / nat_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_nat_inlines_h__
20 #define __included_nat_inlines_h__
21
22 #include <vnet/fib/ip4_fib.h>
23 #include <nat/nat.h>
24 #include <nat/nat_ha.h>
25
26 always_inline u64
27 calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto)
28 {
29   ASSERT (fib_index <= (1 << 14) - 1);
30   ASSERT (proto <= (1 << 3) - 1);
31   return (u64) addr.as_u32 << 32 | (u64) port << 16 | fib_index << 3 |
32     (proto & 0x7);
33 }
34
35 always_inline void
36 split_nat_key (u64 key, ip4_address_t * addr, u16 * port,
37                u32 * fib_index, nat_protocol_t * proto)
38 {
39   if (addr)
40     {
41       addr->as_u32 = key >> 32;
42     }
43   if (port)
44     {
45       *port = (key >> 16) & (u16) ~ 0;
46     }
47   if (fib_index)
48     {
49       *fib_index = key >> 3 & ((1 << 13) - 1);
50     }
51   if (proto)
52     {
53       *proto = key & 0x7;
54     }
55 }
56
57 always_inline void
58 init_nat_k (clib_bihash_kv_8_8_t * kv, ip4_address_t addr, u16 port,
59             u32 fib_index, nat_protocol_t proto)
60 {
61   kv->key = calc_nat_key (addr, port, fib_index, proto);
62   kv->value = ~0ULL;
63 }
64
65 always_inline void
66 init_nat_kv (clib_bihash_kv_8_8_t * kv, ip4_address_t addr, u16 port,
67              u32 fib_index, nat_protocol_t proto, u64 value)
68 {
69   init_nat_k (kv, addr, port, fib_index, proto);
70   kv->value = value;
71 }
72
73 always_inline void
74 init_nat_i2o_k (clib_bihash_kv_8_8_t * kv, snat_session_t * s)
75 {
76   return init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
77                      s->nat_proto);
78 }
79
80 always_inline void
81 init_nat_i2o_kv (clib_bihash_kv_8_8_t * kv, snat_session_t * s, u64 value)
82 {
83   init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
84               s->nat_proto);
85   kv->value = value;
86 }
87
88 always_inline void
89 init_nat_o2i_k (clib_bihash_kv_8_8_t * kv, snat_session_t * s)
90 {
91   return init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
92                      s->nat_proto);
93 }
94
95 always_inline void
96 init_nat_o2i_kv (clib_bihash_kv_8_8_t * kv, snat_session_t * s, u64 value)
97 {
98   init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
99               s->nat_proto);
100   kv->value = value;
101 }
102
103 static inline uword
104 nat_pre_node_fn_inline (vlib_main_t * vm,
105                         vlib_node_runtime_t * node,
106                         vlib_frame_t * frame, u32 def_next)
107 {
108   u32 n_left_from, *from, *to_next;
109   u16 next_index;
110
111   from = vlib_frame_vector_args (frame);
112   n_left_from = frame->n_vectors;
113   next_index = node->cached_next_index;
114
115   while (n_left_from > 0)
116     {
117       u32 n_left_to_next;
118
119       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
120
121       while (n_left_from >= 4 && n_left_to_next >= 2)
122         {
123           u32 next0, next1;
124           u32 arc_next0, arc_next1;
125           u32 bi0, bi1;
126           vlib_buffer_t *b0, *b1;
127
128           /* Prefetch next iteration. */
129           {
130             vlib_buffer_t *p2, *p3;
131
132             p2 = vlib_get_buffer (vm, from[2]);
133             p3 = vlib_get_buffer (vm, from[3]);
134
135             vlib_prefetch_buffer_header (p2, LOAD);
136             vlib_prefetch_buffer_header (p3, LOAD);
137
138             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
139             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD);
140           }
141
142           /* speculatively enqueue b0 and b1 to the current next frame */
143           to_next[0] = bi0 = from[0];
144           to_next[1] = bi1 = from[1];
145           from += 2;
146           to_next += 2;
147           n_left_from -= 2;
148           n_left_to_next -= 2;
149
150           b0 = vlib_get_buffer (vm, bi0);
151           b1 = vlib_get_buffer (vm, bi1);
152
153           next0 = def_next;
154           next1 = def_next;
155
156           vnet_feature_next (&arc_next0, b0);
157           vnet_feature_next (&arc_next1, b1);
158
159           vnet_buffer2 (b0)->nat.arc_next = arc_next0;
160           vnet_buffer2 (b1)->nat.arc_next = arc_next1;
161
162           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
163             {
164               if (b0->flags & VLIB_BUFFER_IS_TRACED)
165                 {
166                   nat_pre_trace_t *t =
167                     vlib_add_trace (vm, node, b0, sizeof (*t));
168                   t->next_index = next0;
169                   t->arc_next_index = arc_next0;
170                 }
171               if (b1->flags & VLIB_BUFFER_IS_TRACED)
172                 {
173                   nat_pre_trace_t *t =
174                     vlib_add_trace (vm, node, b0, sizeof (*t));
175                   t->next_index = next1;
176                   t->arc_next_index = arc_next1;
177                 }
178             }
179
180           /* verify speculative enqueues, maybe switch current next frame */
181           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
182                                            to_next, n_left_to_next,
183                                            bi0, bi1, next0, next1);
184         }
185
186       while (n_left_from > 0 && n_left_to_next > 0)
187         {
188           u32 next0;
189           u32 arc_next0;
190           u32 bi0;
191           vlib_buffer_t *b0;
192
193           /* speculatively enqueue b0 to the current next frame */
194           bi0 = from[0];
195           to_next[0] = bi0;
196           from += 1;
197           to_next += 1;
198           n_left_from -= 1;
199           n_left_to_next -= 1;
200
201           b0 = vlib_get_buffer (vm, bi0);
202           next0 = def_next;
203           vnet_feature_next (&arc_next0, b0);
204           vnet_buffer2 (b0)->nat.arc_next = arc_next0;
205
206           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
207                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
208             {
209               nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
210               t->next_index = next0;
211               t->arc_next_index = arc_next0;
212             }
213
214           /* verify speculative enqueue, maybe switch current next frame */
215           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
216                                            to_next, n_left_to_next,
217                                            bi0, next0);
218         }
219
220       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
221     }
222
223   return frame->n_vectors;
224 }
225
226 always_inline u8
227 is_interface_addr (snat_main_t * sm, vlib_node_runtime_t * node,
228                    u32 sw_if_index0, u32 ip4_addr)
229 {
230   snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
231   ip4_address_t *first_int_addr;
232
233   if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
234     {
235       first_int_addr =
236         ip4_interface_first_address (sm->ip4_main, sw_if_index0,
237                                      0 /* just want the address */ );
238       rt->cached_sw_if_index = sw_if_index0;
239       if (first_int_addr)
240         rt->cached_ip4_address = first_int_addr->as_u32;
241       else
242         rt->cached_ip4_address = 0;
243     }
244
245   if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address))
246     return 1;
247   else
248     return 0;
249 }
250
251 always_inline u8
252 maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index)
253 {
254   if (pool_elts (sm->per_thread_data[thread_index].sessions) >=
255       sm->max_translations_per_thread)
256     return 1;
257
258   return 0;
259 }
260
261 always_inline void
262 user_session_increment (snat_main_t * sm, snat_user_t * u, u8 is_static)
263 {
264   if (u->nsessions + u->nstaticsessions < sm->max_translations_per_user)
265     {
266       if (is_static)
267         u->nstaticsessions++;
268       else
269         u->nsessions++;
270     }
271 }
272
273 always_inline void
274 nat44_delete_user_with_no_session (snat_main_t * sm, snat_user_t * u,
275                                    u32 thread_index)
276 {
277   clib_bihash_kv_8_8_t kv;
278   snat_user_key_t u_key;
279   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
280                                                        thread_index);
281
282   if (u->nstaticsessions == 0 && u->nsessions == 0)
283     {
284       u_key.addr.as_u32 = u->addr.as_u32;
285       u_key.fib_index = u->fib_index;
286       kv.key = u_key.as_u64;
287       pool_put_index (tsm->list_pool, u->sessions_per_user_list_head_index);
288       pool_put (tsm->users, u);
289       clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
290       vlib_set_simple_counter (&sm->total_users, thread_index, 0,
291                                pool_elts (tsm->users));
292     }
293 }
294
295 always_inline void
296 nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
297                       u32 thread_index)
298 {
299   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
300                                                        thread_index);
301   clib_bihash_kv_8_8_t kv, value;
302   snat_user_t *u;
303   const snat_user_key_t u_key = {
304     .addr = ses->in2out.addr,
305     .fib_index = ses->in2out.fib_index
306   };
307   const u8 u_static = snat_is_session_static (ses);
308
309   clib_dlist_remove (tsm->list_pool, ses->per_user_index);
310   pool_put_index (tsm->list_pool, ses->per_user_index);
311   if (sm->endpoint_dependent)
312     {
313       clib_dlist_remove (tsm->lru_pool, ses->lru_index);
314       pool_put_index (tsm->lru_pool, ses->lru_index);
315     }
316   pool_put (tsm->sessions, ses);
317   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
318                            pool_elts (tsm->sessions));
319
320   kv.key = u_key.as_u64;
321   if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
322     {
323       u = pool_elt_at_index (tsm->users, value.value);
324       if (u_static)
325         u->nstaticsessions--;
326       else
327         u->nsessions--;
328
329       nat44_delete_user_with_no_session (sm, u, thread_index);
330     }
331 }
332
333 /** \brief Set TCP session state.
334     @return 1 if session was closed, otherwise 0
335 */
336 always_inline int
337 nat44_set_tcp_session_state_i2o (snat_main_t * sm, f64 now,
338                                  snat_session_t * ses, vlib_buffer_t * b,
339                                  u32 thread_index)
340 {
341   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
342   u8 tcp_flags = vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags;
343   u32 tcp_ack_number = vnet_buffer (b)->ip.reass.tcp_ack_number;
344   u32 tcp_seq_number = vnet_buffer (b)->ip.reass.tcp_seq_number;
345   if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST))
346     ses->state = NAT44_SES_RST;
347   if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST))
348     ses->state = 0;
349   if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
350       (ses->state & NAT44_SES_O2I_SYN))
351     ses->state = 0;
352   if (tcp_flags & TCP_FLAG_SYN)
353     ses->state |= NAT44_SES_I2O_SYN;
354   if (tcp_flags & TCP_FLAG_FIN)
355     {
356       ses->i2o_fin_seq = clib_net_to_host_u32 (tcp_seq_number);
357       ses->state |= NAT44_SES_I2O_FIN;
358     }
359   if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN))
360     {
361       if (clib_net_to_host_u32 (tcp_ack_number) > ses->o2i_fin_seq)
362         {
363           ses->state |= NAT44_SES_O2I_FIN_ACK;
364           if (nat44_is_ses_closed (ses))
365             {                   // if session is now closed, save the timestamp
366               ses->tcp_closed_timestamp = now + sm->tcp_transitory_timeout;
367               ses->last_lru_update = now;
368             }
369         }
370     }
371
372   // move the session to proper LRU
373   if (ses->state)
374     {
375       ses->lru_head_index = tsm->tcp_trans_lru_head_index;
376     }
377   else
378     {
379       ses->lru_head_index = tsm->tcp_estab_lru_head_index;
380     }
381   clib_dlist_remove (tsm->lru_pool, ses->lru_index);
382   clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
383   return 0;
384 }
385
386 always_inline int
387 nat44_set_tcp_session_state_o2i (snat_main_t * sm, f64 now,
388                                  snat_session_t * ses, u8 tcp_flags,
389                                  u32 tcp_ack_number, u32 tcp_seq_number,
390                                  u32 thread_index)
391 {
392   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
393   if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST))
394     ses->state = NAT44_SES_RST;
395   if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST))
396     ses->state = 0;
397   if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
398       (ses->state & NAT44_SES_O2I_SYN))
399     ses->state = 0;
400   if (tcp_flags & TCP_FLAG_SYN)
401     ses->state |= NAT44_SES_O2I_SYN;
402   if (tcp_flags & TCP_FLAG_FIN)
403     {
404       ses->o2i_fin_seq = clib_net_to_host_u32 (tcp_seq_number);
405       ses->state |= NAT44_SES_O2I_FIN;
406     }
407   if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN))
408     {
409       if (clib_net_to_host_u32 (tcp_ack_number) > ses->i2o_fin_seq)
410         ses->state |= NAT44_SES_I2O_FIN_ACK;
411       if (nat44_is_ses_closed (ses))
412         {                       // if session is now closed, save the timestamp
413           ses->tcp_closed_timestamp = now + sm->tcp_transitory_timeout;
414           ses->last_lru_update = now;
415         }
416     }
417   // move the session to proper LRU
418   if (ses->state)
419     {
420       ses->lru_head_index = tsm->tcp_trans_lru_head_index;
421     }
422   else
423     {
424       ses->lru_head_index = tsm->tcp_estab_lru_head_index;
425     }
426   clib_dlist_remove (tsm->lru_pool, ses->lru_index);
427   clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
428   return 0;
429 }
430
431 always_inline u32
432 nat44_session_get_timeout (snat_main_t * sm, snat_session_t * s)
433 {
434   switch (s->nat_proto)
435     {
436     case NAT_PROTOCOL_ICMP:
437       return sm->icmp_timeout;
438     case NAT_PROTOCOL_UDP:
439       return sm->udp_timeout;
440     case NAT_PROTOCOL_TCP:
441       {
442         if (s->state)
443           return sm->tcp_transitory_timeout;
444         else
445           return sm->tcp_established_timeout;
446       }
447     default:
448       return sm->udp_timeout;
449     }
450
451   return 0;
452 }
453
454 always_inline void
455 nat44_session_update_counters (snat_session_t * s, f64 now, uword bytes,
456                                u32 thread_index)
457 {
458   s->last_heard = now;
459   s->total_pkts++;
460   s->total_bytes += bytes;
461   nat_ha_sref (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
462                s->ext_host_port, s->nat_proto, s->out2in.fib_index,
463                s->total_pkts, s->total_bytes, thread_index,
464                &s->ha_last_refreshed, now);
465 }
466
467 /** \brief Per-user LRU list maintenance */
468 always_inline void
469 nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
470                           u32 thread_index)
471 {
472   /* don't update too often - timeout is in magnitude of seconds anyway */
473   if (s->last_heard > s->last_lru_update + 1)
474     {
475       if (!sm->endpoint_dependent)
476         {
477           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
478                              s->per_user_index);
479           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
480                               s->per_user_list_head_index, s->per_user_index);
481         }
482       else
483         {
484           clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
485                              s->lru_index);
486           clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool,
487                               s->lru_head_index, s->lru_index);
488         }
489       s->last_lru_update = s->last_heard;
490     }
491 }
492
493 always_inline void
494 init_ed_k (clib_bihash_kv_16_8_t * kv, ip4_address_t l_addr, u16 l_port,
495            ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto)
496 {
497   kv->key[0] = (u64) r_addr.as_u32 << 32 | l_addr.as_u32;
498   kv->key[1] =
499     (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
500 }
501
502 always_inline void
503 init_ed_kv (clib_bihash_kv_16_8_t * kv, ip4_address_t l_addr, u16 l_port,
504             ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto,
505             u32 thread_index, u32 session_index)
506 {
507   init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto);
508   kv->value = (u64) thread_index << 32 | session_index;
509 }
510
511 always_inline u32
512 ed_value_get_thread_index (clib_bihash_kv_16_8_t * value)
513 {
514   return value->value >> 32;
515 }
516
517 always_inline u32
518 ed_value_get_session_index (clib_bihash_kv_16_8_t * value)
519 {
520   return value->value & ~(u32) 0;
521 }
522
523 always_inline void
524 split_ed_value (clib_bihash_kv_16_8_t * value, u32 * thread_index,
525                 u32 * session_index)
526 {
527   if (thread_index)
528     {
529       *thread_index = ed_value_get_thread_index (value);
530     }
531   if (session_index)
532     {
533       *session_index = ed_value_get_session_index (value);
534     }
535 }
536
537 always_inline void
538 split_ed_kv (clib_bihash_kv_16_8_t * kv,
539              ip4_address_t * l_addr, ip4_address_t * r_addr, u8 * proto,
540              u32 * fib_index, u16 * l_port, u16 * r_port)
541 {
542   if (l_addr)
543     {
544       l_addr->as_u32 = kv->key[0] & (u32) ~ 0;
545     }
546   if (r_addr)
547     {
548       r_addr->as_u32 = kv->key[0] >> 32;
549     }
550   if (r_port)
551     {
552       *r_port = kv->key[1] >> 48;
553     }
554   if (l_port)
555     {
556       *l_port = (kv->key[1] >> 32) & (u16) ~ 0;
557     }
558   if (fib_index)
559     {
560       *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
561     }
562   if (proto)
563     {
564       *proto = kv->key[1] & (u8) ~ 0;
565     }
566 }
567
568 static_always_inline int
569 get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
570                      u32 thread_index, u32 session_index,
571                      nat_protocol_t * nat_proto, u16 * l_port, u16 * r_port,
572                      clib_bihash_kv_16_8_t * kv)
573 {
574   u8 proto;
575   u16 _l_port, _r_port;
576   ip4_address_t *l_addr, *r_addr;
577
578   icmp46_header_t *icmp0;
579   icmp_echo_header_t *echo0, *inner_echo0 = 0;
580   ip4_header_t *inner_ip0 = 0;
581   void *l4_header = 0;
582   icmp46_header_t *inner_icmp0;
583
584   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
585   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
586
587   if (!icmp_type_is_error_message
588       (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
589     {
590       proto = IP_PROTOCOL_ICMP;
591       l_addr = &ip0->src_address;
592       r_addr = &ip0->dst_address;
593       _l_port = vnet_buffer (b)->ip.reass.l4_src_port;
594       _r_port = 0;
595     }
596   else
597     {
598       inner_ip0 = (ip4_header_t *) (echo0 + 1);
599       l4_header = ip4_next_header (inner_ip0);
600       proto = inner_ip0->protocol;
601       r_addr = &inner_ip0->src_address;
602       l_addr = &inner_ip0->dst_address;
603       switch (ip_proto_to_nat_proto (inner_ip0->protocol))
604         {
605         case NAT_PROTOCOL_ICMP:
606           inner_icmp0 = (icmp46_header_t *) l4_header;
607           inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
608           _r_port = 0;
609           _l_port = inner_echo0->identifier;
610           break;
611         case NAT_PROTOCOL_UDP:
612         case NAT_PROTOCOL_TCP:
613           _l_port = ((tcp_udp_header_t *) l4_header)->dst_port;
614           _r_port = ((tcp_udp_header_t *) l4_header)->src_port;
615           break;
616         default:
617           return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
618         }
619     }
620   init_ed_kv (kv, *l_addr, _l_port, *r_addr, _r_port, rx_fib_index, proto,
621               thread_index, session_index);
622   if (nat_proto)
623     {
624       *nat_proto = ip_proto_to_nat_proto (proto);
625     }
626   if (l_port)
627     {
628       *l_port = _l_port;
629     }
630   if (r_port)
631     {
632       *r_port = _r_port;
633     }
634   return 0;
635 }
636
637 static_always_inline int
638 get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
639                      u32 thread_index, u32 session_index,
640                      nat_protocol_t * nat_proto, u16 * l_port, u16 * r_port,
641                      clib_bihash_kv_16_8_t * kv)
642 {
643   icmp46_header_t *icmp0;
644   u8 proto;
645   ip4_address_t *l_addr, *r_addr;
646   u16 _l_port, _r_port;
647   icmp_echo_header_t *echo0, *inner_echo0 = 0;
648   ip4_header_t *inner_ip0;
649   void *l4_header = 0;
650   icmp46_header_t *inner_icmp0;
651
652   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
653   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
654
655   if (!icmp_type_is_error_message
656       (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
657     {
658       proto = IP_PROTOCOL_ICMP;
659       l_addr = &ip0->dst_address;
660       r_addr = &ip0->src_address;
661       _l_port = vnet_buffer (b)->ip.reass.l4_src_port;
662       _r_port = 0;
663     }
664   else
665     {
666       inner_ip0 = (ip4_header_t *) (echo0 + 1);
667       l4_header = ip4_next_header (inner_ip0);
668       proto = inner_ip0->protocol;
669       l_addr = &inner_ip0->src_address;
670       r_addr = &inner_ip0->dst_address;
671       switch (ip_proto_to_nat_proto (inner_ip0->protocol))
672         {
673         case NAT_PROTOCOL_ICMP:
674           inner_icmp0 = (icmp46_header_t *) l4_header;
675           inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
676           _l_port = inner_echo0->identifier;
677           _r_port = 0;
678           break;
679         case NAT_PROTOCOL_UDP:
680         case NAT_PROTOCOL_TCP:
681           _l_port = ((tcp_udp_header_t *) l4_header)->src_port;
682           _r_port = ((tcp_udp_header_t *) l4_header)->dst_port;
683           break;
684         default:
685           return -1;
686         }
687     }
688   init_ed_kv (kv, *l_addr, _l_port, *r_addr, _r_port, rx_fib_index, proto,
689               thread_index, session_index);
690   if (nat_proto)
691     {
692       *nat_proto = ip_proto_to_nat_proto (proto);
693     }
694   if (l_port)
695     {
696       *l_port = _l_port;
697     }
698   if (r_port)
699     {
700       *r_port = _r_port;
701     }
702   return 0;
703 }
704
705 /**
706  * @brief Check if packet should be translated
707  *
708  * Packets aimed at outside interface and external address with active session
709  * should be translated.
710  *
711  * @param sm            NAT main
712  * @param rt            NAT runtime data
713  * @param sw_if_index0  index of the inside interface
714  * @param ip0           IPv4 header
715  * @param proto0        NAT protocol
716  * @param rx_fib_index0 RX FIB index
717  *
718  * @returns 0 if packet should be translated otherwise 1
719  */
720 static inline int
721 snat_not_translate_fast (snat_main_t * sm, vlib_node_runtime_t * node,
722                          u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
723                          u32 rx_fib_index0)
724 {
725   if (sm->out2in_dpo)
726     return 0;
727
728   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
729   nat_outside_fib_t *outside_fib;
730   fib_prefix_t pfx = {
731     .fp_proto = FIB_PROTOCOL_IP4,
732     .fp_len = 32,
733     .fp_addr = {
734                 .ip4.as_u32 = ip0->dst_address.as_u32,
735                 }
736     ,
737   };
738
739   /* Don't NAT packet aimed at the intfc address */
740   if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
741                                         ip0->dst_address.as_u32)))
742     return 1;
743
744   fei = fib_table_lookup (rx_fib_index0, &pfx);
745   if (FIB_NODE_INDEX_INVALID != fei)
746     {
747       u32 sw_if_index = fib_entry_get_resolving_interface (fei);
748       if (sw_if_index == ~0)
749         {
750           vec_foreach (outside_fib, sm->outside_fibs)
751           {
752             fei = fib_table_lookup (outside_fib->fib_index, &pfx);
753             if (FIB_NODE_INDEX_INVALID != fei)
754               {
755                 sw_if_index = fib_entry_get_resolving_interface (fei);
756                 if (sw_if_index != ~0)
757                   break;
758               }
759           }
760         }
761       if (sw_if_index == ~0)
762         return 1;
763
764       snat_interface_t *i;
765       /* *INDENT-OFF* */
766       pool_foreach (i, sm->interfaces, ({
767         /* NAT packet aimed at outside interface */
768         if ((nat_interface_is_outside (i)) && (sw_if_index == i->sw_if_index))
769           return 0;
770       }));
771       /* *INDENT-ON* */
772     }
773
774   return 1;
775 }
776
777 static inline void
778 increment_v4_address (ip4_address_t * a)
779 {
780   u32 v;
781
782   v = clib_net_to_host_u32 (a->as_u32) + 1;
783   a->as_u32 = clib_host_to_net_u32 (v);
784 }
785
786 static_always_inline u16
787 snat_random_port (u16 min, u16 max)
788 {
789   snat_main_t *sm = &snat_main;
790   u32 rwide;
791   u16 r;
792
793   rwide = random_u32 (&sm->random_seed);
794   r = rwide & 0xFFFF;
795   if (r >= min && r <= max)
796     return r;
797
798   return min + (rwide % (max - min + 1));
799 }
800
801 #endif /* __included_nat_inlines_h__ */
802
803 /*
804  * fd.io coding-style-patch-verification: ON
805  *
806  * Local Variables:
807  * eval: (c-set-style "gnu")
808  * End:
809  */