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