VPP-1381: Fix the incorrect if condition when delete session for static mapping
[vpp.git] / src / plugins / nat / nat.c
1 /*
2  * snat.c - simple nat plugin
3  *
4  * Copyright (c) 2016 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/plugin/plugin.h>
22 #include <nat/nat.h>
23 #include <nat/nat_dpo.h>
24 #include <nat/nat_ipfix_logging.h>
25 #include <nat/nat_det.h>
26 #include <nat/nat64.h>
27 #include <nat/nat66.h>
28 #include <nat/dslite.h>
29 #include <nat/nat_reass.h>
30 #include <nat/nat_inlines.h>
31 #include <vnet/fib/fib_table.h>
32 #include <vnet/fib/ip4_fib.h>
33
34 #include <vpp/app/version.h>
35
36 snat_main_t snat_main;
37
38
39 /* Hook up input features */
40 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
41   .arc_name = "ip4-unicast",
42   .node_name = "nat44-in2out",
43   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
44 };
45 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
46   .arc_name = "ip4-unicast",
47   .node_name = "nat44-out2in",
48   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
49                                "ip4-dhcp-client-detect"),
50 };
51 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
52   .arc_name = "ip4-unicast",
53   .node_name = "nat44-classify",
54   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
55 };
56 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
57   .arc_name = "ip4-unicast",
58   .node_name = "nat44-det-in2out",
59   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
60 };
61 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
62   .arc_name = "ip4-unicast",
63   .node_name = "nat44-det-out2in",
64   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
65                                "ip4-dhcp-client-detect"),
66 };
67 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
68   .arc_name = "ip4-unicast",
69   .node_name = "nat44-det-classify",
70   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
71 };
72 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
73   .arc_name = "ip4-unicast",
74   .node_name = "nat44-ed-in2out",
75   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
76 };
77 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
78   .arc_name = "ip4-unicast",
79   .node_name = "nat44-ed-out2in",
80   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
81                                "ip4-dhcp-client-detect"),
82 };
83 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
84   .arc_name = "ip4-unicast",
85   .node_name = "nat44-ed-classify",
86   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
87 };
88 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
89   .arc_name = "ip4-unicast",
90   .node_name = "nat44-in2out-worker-handoff",
91   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
92 };
93 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
94   .arc_name = "ip4-unicast",
95   .node_name = "nat44-out2in-worker-handoff",
96   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
97                                "ip4-dhcp-client-detect"),
98 };
99 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
100   .arc_name = "ip4-unicast",
101   .node_name = "nat44-handoff-classify",
102   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
103 };
104 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
105   .arc_name = "ip4-unicast",
106   .node_name = "nat44-in2out-fast",
107   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
108 };
109 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
110   .arc_name = "ip4-unicast",
111   .node_name = "nat44-out2in-fast",
112   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
113                                "ip4-dhcp-client-detect"),
114 };
115 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
116   .arc_name = "ip4-unicast",
117   .node_name = "nat44-hairpin-dst",
118   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
119 };
120 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
121   .arc_name = "ip4-unicast",
122   .node_name = "nat44-ed-hairpin-dst",
123   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
124 };
125
126 /* Hook up output features */
127 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
128   .arc_name = "ip4-output",
129   .node_name = "nat44-in2out-output",
130   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
131 };
132 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
133   .arc_name = "ip4-output",
134   .node_name = "nat44-in2out-output-worker-handoff",
135   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
136 };
137 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
138   .arc_name = "ip4-output",
139   .node_name = "nat44-hairpin-src",
140   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
141 };
142 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
143   .arc_name = "ip4-output",
144   .node_name = "nat44-ed-in2out-output",
145   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
146 };
147 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
148   .arc_name = "ip4-output",
149   .node_name = "nat44-ed-hairpin-src",
150   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
151 };
152
153 /* Hook up ip4-local features */
154 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
155 {
156   .arc_name = "ip4-local",
157   .node_name = "nat44-hairpinning",
158   .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
159 };
160 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
161 {
162   .arc_name = "ip4-local",
163   .node_name = "nat44-ed-hairpinning",
164   .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
165 };
166
167
168 /* *INDENT-OFF* */
169 VLIB_PLUGIN_REGISTER () = {
170     .version = VPP_BUILD_VER,
171     .description = "Network Address Translation",
172 };
173 /* *INDENT-ON* */
174
175 vlib_node_registration_t nat44_classify_node;
176 vlib_node_registration_t nat44_ed_classify_node;
177 vlib_node_registration_t nat44_det_classify_node;
178 vlib_node_registration_t nat44_handoff_classify_node;
179
180 typedef enum {
181   NAT44_CLASSIFY_NEXT_IN2OUT,
182   NAT44_CLASSIFY_NEXT_OUT2IN,
183   NAT44_CLASSIFY_N_NEXT,
184 } nat44_classify_next_t;
185
186 void
187 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
188 {
189   snat_session_key_t key;
190   clib_bihash_kv_8_8_t kv;
191   nat_ed_ses_key_t ed_key;
192   clib_bihash_kv_16_8_t ed_kv;
193   int i;
194   snat_address_t *a;
195   snat_main_per_thread_data_t *tsm =
196     vec_elt_at_index (sm->per_thread_data, thread_index);
197
198   if (is_fwd_bypass_session (s))
199     {
200       ed_key.l_addr = s->in2out.addr;
201       ed_key.r_addr = s->ext_host_addr;
202       ed_key.l_port = s->in2out.port;
203       ed_key.r_port = s->ext_host_port;
204       ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
205       ed_key.fib_index = 0;
206       ed_kv.key[0] = ed_key.as_u64[0];
207       ed_kv.key[1] = ed_key.as_u64[1];
208       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
209         nat_log_warn ("in2out_ed key del failed");
210       return;
211     }
212
213   /* session lookup tables */
214   if (is_ed_session (s))
215     {
216       ed_key.l_addr = s->out2in.addr;
217       ed_key.r_addr = s->ext_host_addr;
218       ed_key.fib_index = s->out2in.fib_index;
219       if (snat_is_unk_proto_session (s))
220         {
221           ed_key.proto = s->in2out.port;
222           ed_key.r_port = 0;
223           ed_key.l_port = 0;
224         }
225       else
226         {
227           ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
228           ed_key.l_port = s->out2in.port;
229           ed_key.r_port = s->ext_host_port;
230         }
231       ed_kv.key[0] = ed_key.as_u64[0];
232       ed_kv.key[1] = ed_key.as_u64[1];
233       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
234         nat_log_warn ("out2in_ed key del failed");
235
236       ed_key.l_addr = s->in2out.addr;
237       ed_key.fib_index = s->in2out.fib_index;
238       if (!snat_is_unk_proto_session (s))
239         ed_key.l_port = s->in2out.port;
240       if (is_twice_nat_session (s))
241         {
242           ed_key.r_addr = s->ext_host_nat_addr;
243           ed_key.r_port = s->ext_host_nat_port;
244         }
245       ed_kv.key[0] = ed_key.as_u64[0];
246       ed_kv.key[1] = ed_key.as_u64[1];
247       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
248         nat_log_warn ("in2out_ed key del failed");
249     }
250   else
251     {
252       kv.key = s->in2out.as_u64;
253       if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
254         nat_log_warn ("in2out key del failed");
255       kv.key = s->out2in.as_u64;
256       if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
257         nat_log_warn ("out2in key del failed");
258     }
259
260   if (snat_is_unk_proto_session (s))
261     return;
262
263   /* log NAT event */
264   snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
265                                       s->out2in.addr.as_u32,
266                                       s->in2out.protocol,
267                                       s->in2out.port,
268                                       s->out2in.port,
269                                       s->in2out.fib_index);
270
271   /* Twice NAT address and port for external host */
272   if (is_twice_nat_session (s))
273     {
274       for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
275         {
276           key.protocol = s->in2out.protocol;
277           key.port = s->ext_host_nat_port;
278           a = sm->twice_nat_addresses + i;
279           if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
280             {
281               snat_free_outside_address_and_port (sm->twice_nat_addresses,
282                                                   thread_index, &key, i);
283               break;
284             }
285         }
286     }
287
288   if (snat_is_session_static (s))
289     return;
290
291   if (s->outside_address_index != ~0)
292     snat_free_outside_address_and_port (sm->addresses, thread_index,
293                                         &s->out2in, s->outside_address_index);
294 }
295
296 snat_user_t *
297 nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr, u32 fib_index,
298                         u32 thread_index)
299 {
300   snat_user_t *u = 0;
301   snat_user_key_t user_key;
302   clib_bihash_kv_8_8_t kv, value;
303   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
304   dlist_elt_t * per_user_list_head_elt;
305
306   user_key.addr.as_u32 = addr->as_u32;
307   user_key.fib_index = fib_index;
308   kv.key = user_key.as_u64;
309
310   /* Ever heard of the "user" = src ip4 address before? */
311   if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
312     {
313       /* no, make a new one */
314       pool_get (tsm->users, u);
315       memset (u, 0, sizeof (*u));
316       u->addr.as_u32 = addr->as_u32;
317       u->fib_index = fib_index;
318
319       pool_get (tsm->list_pool, per_user_list_head_elt);
320
321       u->sessions_per_user_list_head_index = per_user_list_head_elt -
322         tsm->list_pool;
323
324       clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
325
326       kv.value = u - tsm->users;
327
328       /* add user */
329       if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
330         nat_log_warn ("user_hash keay add failed");
331
332       clib_warning("%U %d", format_ip4_address, addr, fib_index);
333     }
334   else
335     {
336       u = pool_elt_at_index (tsm->users, value.value);
337     }
338
339   return u;
340 }
341
342 snat_session_t *
343 nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index)
344 {
345   snat_session_t *s;
346   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
347   u32 oldest_per_user_translation_list_index, session_index;
348   dlist_elt_t * oldest_per_user_translation_list_elt;
349   dlist_elt_t * per_user_translation_list_elt;
350
351   /* Over quota? Recycle the least recently used translation */
352   if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
353     {
354       oldest_per_user_translation_list_index =
355         clib_dlist_remove_head (tsm->list_pool,
356                                 u->sessions_per_user_list_head_index);
357
358       ASSERT (oldest_per_user_translation_list_index != ~0);
359
360       /* Add it back to the end of the LRU list */
361       clib_dlist_addtail (tsm->list_pool,
362                           u->sessions_per_user_list_head_index,
363                           oldest_per_user_translation_list_index);
364       /* Get the list element */
365       oldest_per_user_translation_list_elt =
366         pool_elt_at_index (tsm->list_pool,
367                            oldest_per_user_translation_list_index);
368
369       /* Get the session index from the list element */
370       session_index = oldest_per_user_translation_list_elt->value;
371
372       /* Get the session */
373       s = pool_elt_at_index (tsm->sessions, session_index);
374       nat_free_session_data (sm, s, thread_index);
375       if (snat_is_session_static(s))
376         u->nstaticsessions--;
377       else
378         u->nsessions--;
379       s->outside_address_index = ~0;
380       s->flags = 0;
381       s->total_bytes = 0;
382       s->total_pkts = 0;
383       s->state = 0;
384       s->ext_host_addr.as_u32 = 0;
385       s->ext_host_port = 0;
386       s->ext_host_nat_addr.as_u32 = 0;
387       s->ext_host_nat_port = 0;
388     }
389   else
390     {
391       pool_get (tsm->sessions, s);
392       memset (s, 0, sizeof (*s));
393       s->outside_address_index = ~0;
394
395       /* Create list elts */
396       pool_get (tsm->list_pool, per_user_translation_list_elt);
397       clib_dlist_init (tsm->list_pool,
398                        per_user_translation_list_elt - tsm->list_pool);
399
400       per_user_translation_list_elt->value = s - tsm->sessions;
401       s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
402       s->per_user_list_head_index = u->sessions_per_user_list_head_index;
403
404       clib_dlist_addtail (tsm->list_pool,
405                           s->per_user_list_head_index,
406                           per_user_translation_list_elt - tsm->list_pool);
407     }
408
409   return s;
410 }
411
412 typedef struct {
413   u8 next_in2out;
414 } nat44_classify_trace_t;
415
416 static u8 * format_nat44_classify_trace (u8 * s, va_list * args)
417 {
418   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
419   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
420   nat44_classify_trace_t *t = va_arg (*args, nat44_classify_trace_t *);
421   char *next;
422
423   next = t->next_in2out ? "nat44-in2out" : "nat44-out2in";
424
425   s = format (s, "nat44-classify: next %s", next);
426
427   return s;
428 }
429
430 static inline uword
431 nat44_classify_node_fn_inline (vlib_main_t * vm,
432                                vlib_node_runtime_t * node,
433                                vlib_frame_t * frame,
434                                int is_ed)
435 {
436   u32 n_left_from, * from, * to_next;
437   nat44_classify_next_t next_index;
438   snat_main_t *sm = &snat_main;
439   snat_static_mapping_t *m;
440   u32 thread_index = vm->thread_index;
441   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
442
443   from = vlib_frame_vector_args (frame);
444   n_left_from = frame->n_vectors;
445   next_index = node->cached_next_index;
446
447   while (n_left_from > 0)
448     {
449       u32 n_left_to_next;
450
451       vlib_get_next_frame (vm, node, next_index,
452                            to_next, n_left_to_next);
453
454       while (n_left_from > 0 && n_left_to_next > 0)
455         {
456           u32 bi0;
457           vlib_buffer_t *b0;
458           u32 next0 = NAT44_CLASSIFY_NEXT_IN2OUT, sw_if_index0, rx_fib_index0;
459           ip4_header_t *ip0;
460           snat_address_t *ap;
461           snat_session_key_t m_key0;
462           clib_bihash_kv_8_8_t kv0, value0;
463           clib_bihash_kv_16_8_t ed_kv0, ed_value0;
464           udp_header_t *udp0;
465
466           /* speculatively enqueue b0 to the current next frame */
467           bi0 = from[0];
468           to_next[0] = bi0;
469           from += 1;
470           to_next += 1;
471           n_left_from -= 1;
472           n_left_to_next -= 1;
473
474           b0 = vlib_get_buffer (vm, bi0);
475           ip0 = vlib_buffer_get_current (b0);
476           udp0 = ip4_next_header (ip0);
477
478           if (is_ed)
479             {
480               sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
481               rx_fib_index0 =
482                 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
483                                                      sw_if_index0);
484               make_ed_kv (&ed_kv0, &ip0->src_address, &ip0->dst_address,
485                           ip0->protocol, rx_fib_index0, udp0->src_port,
486                           udp0->dst_port);
487               if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &ed_kv0, &ed_value0))
488                 goto enqueue0;
489             }
490
491           vec_foreach (ap, sm->addresses)
492             {
493               if (ip0->dst_address.as_u32 == ap->addr.as_u32)
494                 {
495                   next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
496                   goto enqueue0;
497                 }
498             }
499
500           if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
501             {
502               m_key0.addr = ip0->dst_address;
503               m_key0.port = 0;
504               m_key0.protocol = 0;
505               m_key0.fib_index = 0;
506               kv0.key = m_key0.as_u64;
507               if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
508                 {
509                   m = pool_elt_at_index (sm->static_mappings, value0.value);
510                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
511                     next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
512                   goto enqueue0;
513                 }
514               m_key0.port = clib_net_to_host_u16 (udp0->dst_port);
515               m_key0.protocol = ip_proto_to_snat_proto (ip0->protocol);
516               kv0.key = m_key0.as_u64;
517               if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
518                 {
519                   m = pool_elt_at_index (sm->static_mappings, value0.value);
520                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
521                     next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
522                 }
523             }
524
525         enqueue0:
526           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
527                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
528             {
529               nat44_classify_trace_t *t =
530                   vlib_add_trace (vm, node, b0, sizeof (*t));
531               t->next_in2out = next0 == NAT44_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
532             }
533
534           /* verify speculative enqueue, maybe switch current next frame */
535           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
536                                            to_next, n_left_to_next,
537                                            bi0, next0);
538         }
539
540       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
541     }
542
543   return frame->n_vectors;
544 }
545
546 static uword
547 nat44_classify_node_fn (vlib_main_t * vm,
548                         vlib_node_runtime_t * node,
549                         vlib_frame_t * frame)
550 {
551   return nat44_classify_node_fn_inline (vm, node, frame, 0);
552 };
553
554 VLIB_REGISTER_NODE (nat44_classify_node) = {
555   .function = nat44_classify_node_fn,
556   .name = "nat44-classify",
557   .vector_size = sizeof (u32),
558   .format_trace = format_nat44_classify_trace,
559   .type = VLIB_NODE_TYPE_INTERNAL,
560   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
561   .next_nodes = {
562     [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
563     [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
564   },
565 };
566
567 VLIB_NODE_FUNCTION_MULTIARCH (nat44_classify_node,
568                               nat44_classify_node_fn);
569 static uword
570 nat44_ed_classify_node_fn (vlib_main_t * vm,
571                            vlib_node_runtime_t * node,
572                            vlib_frame_t * frame)
573 {
574   return nat44_classify_node_fn_inline (vm, node, frame, 1);
575 };
576
577 VLIB_REGISTER_NODE (nat44_ed_classify_node) = {
578   .function = nat44_ed_classify_node_fn,
579   .name = "nat44-ed-classify",
580   .vector_size = sizeof (u32),
581   .format_trace = format_nat44_classify_trace,
582   .type = VLIB_NODE_TYPE_INTERNAL,
583   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
584   .next_nodes = {
585     [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-ed-in2out",
586     [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-ed-out2in",
587   },
588 };
589
590 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_classify_node,
591                               nat44_ed_classify_node_fn);
592
593 static uword
594 nat44_det_classify_node_fn (vlib_main_t * vm,
595                             vlib_node_runtime_t * node,
596                             vlib_frame_t * frame)
597 {
598   return nat44_classify_node_fn_inline (vm, node, frame, 0);
599 };
600
601 VLIB_REGISTER_NODE (nat44_det_classify_node) = {
602   .function = nat44_det_classify_node_fn,
603   .name = "nat44-det-classify",
604   .vector_size = sizeof (u32),
605   .format_trace = format_nat44_classify_trace,
606   .type = VLIB_NODE_TYPE_INTERNAL,
607   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
608   .next_nodes = {
609     [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out",
610     [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in",
611   },
612 };
613
614 VLIB_NODE_FUNCTION_MULTIARCH (nat44_det_classify_node,
615                               nat44_det_classify_node_fn);
616
617 static uword
618 nat44_handoff_classify_node_fn (vlib_main_t * vm,
619                                 vlib_node_runtime_t * node,
620                                 vlib_frame_t * frame)
621 {
622   return nat44_classify_node_fn_inline (vm, node, frame, 0);
623 };
624
625 VLIB_REGISTER_NODE (nat44_handoff_classify_node) = {
626   .function = nat44_handoff_classify_node_fn,
627   .name = "nat44-handoff-classify",
628   .vector_size = sizeof (u32),
629   .format_trace = format_nat44_classify_trace,
630   .type = VLIB_NODE_TYPE_INTERNAL,
631   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
632   .next_nodes = {
633     [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out-worker-handoff",
634     [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in-worker-handoff",
635   },
636 };
637
638 VLIB_NODE_FUNCTION_MULTIARCH (nat44_handoff_classify_node,
639                               nat44_handoff_classify_node_fn);
640
641 /**
642  * @brief Add/del NAT address to FIB.
643  *
644  * Add the external NAT address to the FIB as receive entries. This ensures
645  * that VPP will reply to ARP for this address and we don't need to enable
646  * proxy ARP on the outside interface.
647  *
648  * @param addr IPv4 address.
649  * @param plen address prefix length
650  * @param sw_if_index Interface.
651  * @param is_add If 0 delete, otherwise add.
652  */
653 void
654 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
655                           int is_add)
656 {
657   fib_prefix_t prefix = {
658     .fp_len = p_len,
659     .fp_proto = FIB_PROTOCOL_IP4,
660     .fp_addr = {
661         .ip4.as_u32 = addr->as_u32,
662     },
663   };
664   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
665
666   if (is_add)
667     fib_table_entry_update_one_path(fib_index,
668                                     &prefix,
669                                     FIB_SOURCE_PLUGIN_LOW,
670                                     (FIB_ENTRY_FLAG_CONNECTED |
671                                      FIB_ENTRY_FLAG_LOCAL |
672                                      FIB_ENTRY_FLAG_EXCLUSIVE),
673                                     DPO_PROTO_IP4,
674                                     NULL,
675                                     sw_if_index,
676                                     ~0,
677                                     1,
678                                     NULL,
679                                     FIB_ROUTE_PATH_FLAG_NONE);
680   else
681     fib_table_entry_delete(fib_index,
682                            &prefix,
683                            FIB_SOURCE_PLUGIN_LOW);
684 }
685
686 int snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id,
687                        u8 twice_nat)
688 {
689   snat_address_t * ap;
690   snat_interface_t *i;
691   vlib_thread_main_t *tm = vlib_get_thread_main ();
692
693   if (twice_nat && !sm->endpoint_dependent)
694     return VNET_API_ERROR_FEATURE_DISABLED;
695
696   /* Check if address already exists */
697   vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
698     {
699       if (ap->addr.as_u32 == addr->as_u32)
700         return VNET_API_ERROR_VALUE_EXIST;
701     }
702
703   if (twice_nat)
704     vec_add2 (sm->twice_nat_addresses, ap, 1);
705   else
706     vec_add2 (sm->addresses, ap, 1);
707
708   ap->addr = *addr;
709   if (vrf_id != ~0)
710     ap->fib_index =
711       fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
712                                          FIB_SOURCE_PLUGIN_LOW);
713   else
714     ap->fib_index = ~0;
715 #define _(N, i, n, s) \
716   clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
717   ap->busy_##n##_ports = 0; \
718   vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
719   foreach_snat_protocol
720 #undef _
721
722   if (twice_nat)
723     return 0;
724
725   /* Add external address to FIB */
726   pool_foreach (i, sm->interfaces,
727   ({
728     if (nat_interface_is_inside(i) || sm->out2in_dpo)
729       continue;
730
731     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
732     break;
733   }));
734   pool_foreach (i, sm->output_feature_interfaces,
735   ({
736     if (nat_interface_is_inside(i) || sm->out2in_dpo)
737       continue;
738
739     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
740     break;
741   }));
742
743   return 0;
744 }
745
746 static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
747                                                    ip4_address_t addr)
748 {
749   snat_static_mapping_t *m;
750   pool_foreach (m, sm->static_mappings,
751   ({
752       if (m->external_addr.as_u32 == addr.as_u32)
753         return 1;
754   }));
755
756   return 0;
757 }
758
759 void increment_v4_address (ip4_address_t * a)
760 {
761   u32 v;
762
763   v = clib_net_to_host_u32(a->as_u32) + 1;
764   a->as_u32 = clib_host_to_net_u32(v);
765 }
766
767 static void
768 snat_add_static_mapping_when_resolved (snat_main_t * sm,
769                                        ip4_address_t l_addr,
770                                        u16 l_port,
771                                        u32 sw_if_index,
772                                        u16 e_port,
773                                        u32 vrf_id,
774                                        snat_protocol_t proto,
775                                        int addr_only,
776                                        int is_add,
777                                        u8 * tag)
778 {
779   snat_static_map_resolve_t *rp;
780
781   vec_add2 (sm->to_resolve, rp, 1);
782   rp->l_addr.as_u32 = l_addr.as_u32;
783   rp->l_port = l_port;
784   rp->sw_if_index = sw_if_index;
785   rp->e_port = e_port;
786   rp->vrf_id = vrf_id;
787   rp->proto = proto;
788   rp->addr_only = addr_only;
789   rp->is_add = is_add;
790   rp->tag = vec_dup (tag);
791 }
792
793 /**
794  * @brief Add static mapping.
795  *
796  * Create static mapping between local addr+port and external addr+port.
797  *
798  * @param l_addr Local IPv4 address.
799  * @param e_addr External IPv4 address.
800  * @param l_port Local port number.
801  * @param e_port External port number.
802  * @param vrf_id VRF ID.
803  * @param addr_only If 0 address port and pair mapping, otherwise address only.
804  * @param sw_if_index External port instead of specific IP address.
805  * @param is_add If 0 delete static mapping, otherwise add.
806  * @param twice_nat If value is TWICE_NAT then translate external host address
807  *                  and port.
808  *                  If value is TWICE_NAT_SELF then translate external host
809  *                  address and port whenever external host address equals
810  *                  local address of internal host.
811  * @param out2in_only If 1 rule match only out2in direction
812  * @param tag - opaque string tag
813  *
814  * @returns
815  */
816 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
817                             u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
818                             u32 sw_if_index, snat_protocol_t proto, int is_add,
819                             twice_nat_type_t twice_nat, u8 out2in_only,
820                             u8 * tag)
821 {
822   snat_main_t * sm = &snat_main;
823   snat_static_mapping_t *m;
824   snat_session_key_t m_key;
825   clib_bihash_kv_8_8_t kv, value;
826   snat_address_t *a = 0;
827   u32 fib_index = ~0;
828   uword * p;
829   snat_interface_t *interface;
830   int i;
831   snat_main_per_thread_data_t *tsm;
832   snat_user_key_t u_key;
833   snat_user_t *u;
834   dlist_elt_t * head, * elt;
835   u32 elt_index, head_index;
836   u32 ses_index;
837   u64 user_index;
838   snat_session_t * s;
839   snat_static_map_resolve_t *rp, *rp_match = 0;
840
841   if (!sm->endpoint_dependent)
842     {
843       if (twice_nat || out2in_only)
844         return VNET_API_ERROR_FEATURE_DISABLED;
845     }
846
847   /* If the external address is a specific interface address */
848   if (sw_if_index != ~0)
849     {
850       ip4_address_t * first_int_addr;
851
852       for (i = 0; i < vec_len (sm->to_resolve); i++)
853         {
854           rp = sm->to_resolve + i;
855           if (rp->sw_if_index != sw_if_index ||
856               rp->l_addr.as_u32 != l_addr.as_u32 ||
857               rp->vrf_id != vrf_id || rp->addr_only != addr_only)
858             continue;
859
860           if (!addr_only)
861             {
862               if (rp->l_port != l_port || rp->e_port != e_port || rp->proto != proto)
863                 continue;
864             }
865
866           rp_match = rp;
867           break;
868         }
869
870       /* Might be already set... */
871       first_int_addr = ip4_interface_first_address
872         (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
873
874       if (is_add)
875         {
876           if (rp_match)
877             return VNET_API_ERROR_VALUE_EXIST;
878
879           snat_add_static_mapping_when_resolved
880             (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
881              addr_only,  is_add, tag);
882
883           /* DHCP resolution required? */
884           if (first_int_addr == 0)
885             {
886               return 0;
887             }
888           else
889             {
890               e_addr.as_u32 = first_int_addr->as_u32;
891               /* Identity mapping? */
892               if (l_addr.as_u32 == 0)
893                 l_addr.as_u32 = e_addr.as_u32;
894             }
895         }
896       else
897         {
898           if (!rp_match)
899             return VNET_API_ERROR_NO_SUCH_ENTRY;
900
901           vec_del1 (sm->to_resolve, i);
902
903           if (first_int_addr)
904             {
905               e_addr.as_u32 = first_int_addr->as_u32;
906               /* Identity mapping? */
907               if (l_addr.as_u32 == 0)
908                 l_addr.as_u32 = e_addr.as_u32;
909             }
910           else
911             return 0;
912         }
913     }
914
915   m_key.addr = e_addr;
916   m_key.port = addr_only ? 0 : e_port;
917   m_key.protocol = addr_only ? 0 : proto;
918   m_key.fib_index = 0;
919   kv.key = m_key.as_u64;
920   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
921     m = 0;
922   else
923     m = pool_elt_at_index (sm->static_mappings, value.value);
924
925   if (is_add)
926     {
927       if (m)
928         return VNET_API_ERROR_VALUE_EXIST;
929
930       if (twice_nat && addr_only)
931         return VNET_API_ERROR_UNSUPPORTED;
932
933       /* Convert VRF id to FIB index */
934       if (vrf_id != ~0)
935         {
936           p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
937           if (!p)
938             return VNET_API_ERROR_NO_SUCH_FIB;
939           fib_index = p[0];
940         }
941       /* If not specified use inside VRF id from SNAT plugin startup config */
942       else
943         {
944           fib_index = sm->inside_fib_index;
945           vrf_id = sm->inside_vrf_id;
946         }
947
948       if (!out2in_only)
949         {
950           m_key.addr = l_addr;
951           m_key.port = addr_only ? 0 : l_port;
952           m_key.protocol = addr_only ? 0 : proto;
953           m_key.fib_index = fib_index;
954           kv.key = m_key.as_u64;
955           if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
956             return VNET_API_ERROR_VALUE_EXIST;
957         }
958
959       /* Find external address in allocated addresses and reserve port for
960          address and port pair mapping when dynamic translations enabled */
961       if (!(addr_only || sm->static_mapping_only || out2in_only))
962         {
963           for (i = 0; i < vec_len (sm->addresses); i++)
964             {
965               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
966                 {
967                   a = sm->addresses + i;
968                   /* External port must be unused */
969                   switch (proto)
970                     {
971 #define _(N, j, n, s) \
972                     case SNAT_PROTOCOL_##N: \
973                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
974                         return VNET_API_ERROR_INVALID_VALUE; \
975                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
976                       if (e_port > 1024) \
977                         { \
978                           a->busy_##n##_ports++; \
979                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
980                         } \
981                       break;
982                       foreach_snat_protocol
983 #undef _
984                     default:
985                       nat_log_info ("unknown protocol");
986                       return VNET_API_ERROR_INVALID_VALUE_2;
987                     }
988                   break;
989                 }
990             }
991           /* External address must be allocated */
992           if (!a && (l_addr.as_u32 != e_addr.as_u32))
993             {
994               if (sw_if_index != ~0)
995                 {
996                   for (i = 0; i < vec_len (sm->to_resolve); i++)
997                     {
998                       rp = sm->to_resolve + i;
999                       if (rp->addr_only)
1000                          continue;
1001                       if (rp->sw_if_index != sw_if_index &&
1002                           rp->l_addr.as_u32 != l_addr.as_u32 &&
1003                           rp->vrf_id != vrf_id && rp->l_port != l_port &&
1004                           rp->e_port != e_port && rp->proto != proto)
1005                         continue;
1006
1007                       vec_del1 (sm->to_resolve, i);
1008                       break;
1009                     }
1010                 }
1011               return VNET_API_ERROR_NO_SUCH_ENTRY;
1012             }
1013         }
1014
1015       pool_get (sm->static_mappings, m);
1016       memset (m, 0, sizeof (*m));
1017       m->tag = vec_dup (tag);
1018       m->local_addr = l_addr;
1019       m->external_addr = e_addr;
1020       m->addr_only = addr_only;
1021       m->vrf_id = vrf_id;
1022       m->fib_index = fib_index;
1023       m->twice_nat = twice_nat;
1024       m->out2in_only = out2in_only;
1025       if (!addr_only)
1026         {
1027           m->local_port = l_port;
1028           m->external_port = e_port;
1029           m->proto = proto;
1030         }
1031
1032       if (sm->num_workers > 1)
1033         {
1034           ip4_header_t ip = {
1035             .src_address = m->local_addr,
1036           };
1037           vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index));
1038           tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1039         }
1040       else
1041         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1042
1043       m_key.addr = m->local_addr;
1044       m_key.port = m->local_port;
1045       m_key.protocol = m->proto;
1046       m_key.fib_index = m->fib_index;
1047       kv.key = m_key.as_u64;
1048       kv.value = m - sm->static_mappings;
1049       if (!out2in_only)
1050         clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
1051
1052       m_key.addr = m->external_addr;
1053       m_key.port = m->external_port;
1054       m_key.fib_index = 0;
1055       kv.key = m_key.as_u64;
1056       kv.value = m - sm->static_mappings;
1057       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
1058
1059       /* Delete dynamic sessions matching local address (+ local port) */
1060       if (!(sm->static_mapping_only))
1061         {
1062           u_key.addr = m->local_addr;
1063           u_key.fib_index = m->fib_index;
1064           kv.key = u_key.as_u64;
1065           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1066             {
1067               user_index = value.value;
1068               u = pool_elt_at_index (tsm->users, user_index);
1069               if (u->nsessions)
1070                 {
1071                   head_index = u->sessions_per_user_list_head_index;
1072                   head = pool_elt_at_index (tsm->list_pool, head_index);
1073                   elt_index = head->next;
1074                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1075                   ses_index = elt->value;
1076                   while (ses_index != ~0)
1077                     {
1078                       s =  pool_elt_at_index (tsm->sessions, ses_index);
1079                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1080                       ses_index = elt->value;
1081
1082                       if (snat_is_session_static (s))
1083                         continue;
1084
1085                       if (!addr_only && (clib_net_to_host_u16 (s->in2out.port) != m->local_port))
1086                         continue;
1087
1088                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1089                       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1090
1091                       if (!addr_only && !sm->endpoint_dependent)
1092                         break;
1093                     }
1094                 }
1095             }
1096         }
1097     }
1098   else
1099     {
1100       if (!m)
1101         {
1102           if (sw_if_index != ~0)
1103             return 0;
1104           else
1105             return VNET_API_ERROR_NO_SUCH_ENTRY;
1106         }
1107
1108       /* Free external address port */
1109       if (!(addr_only || sm->static_mapping_only || out2in_only))
1110         {
1111           for (i = 0; i < vec_len (sm->addresses); i++)
1112             {
1113               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1114                 {
1115                   a = sm->addresses + i;
1116                   switch (proto)
1117                     {
1118 #define _(N, j, n, s) \
1119                     case SNAT_PROTOCOL_##N: \
1120                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1121                       if (e_port > 1024) \
1122                         { \
1123                           a->busy_##n##_ports--; \
1124                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
1125                         } \
1126                       break;
1127                       foreach_snat_protocol
1128 #undef _
1129                     default:
1130                       nat_log_info ("unknown protocol");
1131                       return VNET_API_ERROR_INVALID_VALUE_2;
1132                     }
1133                   break;
1134                 }
1135             }
1136         }
1137
1138       if (sm->num_workers > 1)
1139         tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1140       else
1141         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1142
1143       m_key.addr = m->local_addr;
1144       m_key.port = m->local_port;
1145       m_key.protocol = m->proto;
1146       m_key.fib_index = m->fib_index;
1147       kv.key = m_key.as_u64;
1148       if (!out2in_only)
1149         clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
1150
1151       m_key.addr = m->external_addr;
1152       m_key.port = m->external_port;
1153       m_key.fib_index = 0;
1154       kv.key = m_key.as_u64;
1155       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
1156
1157       /* Delete session(s) for static mapping if exist */
1158       if (!(sm->static_mapping_only) ||
1159           (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1160         {
1161           u_key.addr = m->local_addr;
1162           u_key.fib_index = m->fib_index;
1163           kv.key = u_key.as_u64;
1164           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1165             {
1166               user_index = value.value;
1167               u = pool_elt_at_index (tsm->users, user_index);
1168               if (u->nstaticsessions)
1169                 {
1170                   head_index = u->sessions_per_user_list_head_index;
1171                   head = pool_elt_at_index (tsm->list_pool, head_index);
1172                   elt_index = head->next;
1173                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1174                   ses_index = elt->value;
1175                   while (ses_index != ~0)
1176                     {
1177                       s =  pool_elt_at_index (tsm->sessions, ses_index);
1178                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1179                       ses_index = elt->value;
1180
1181                       if (!addr_only)
1182                         {
1183                           if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1184                               (clib_net_to_host_u16 (s->out2in.port) != e_port))
1185                             continue;
1186                         }
1187
1188                       if (is_lb_session (s))
1189                         continue;
1190
1191                       if (!snat_is_session_static (s))
1192                         continue;
1193
1194                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1195                       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1196
1197                       if (!addr_only && !sm->endpoint_dependent)
1198                         break;
1199                     }
1200                 }
1201             }
1202         }
1203
1204       vec_free (m->tag);
1205       vec_free (m->workers);
1206       /* Delete static mapping from pool */
1207       pool_put (sm->static_mappings, m);
1208     }
1209
1210   if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1211     return 0;
1212
1213   /* Add/delete external address to FIB */
1214   pool_foreach (interface, sm->interfaces,
1215   ({
1216     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1217       continue;
1218
1219     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1220     break;
1221   }));
1222   pool_foreach (interface, sm->output_feature_interfaces,
1223   ({
1224     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1225       continue;
1226
1227     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1228     break;
1229   }));
1230
1231   return 0;
1232 }
1233
1234 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1235                                      snat_protocol_t proto,
1236                                      nat44_lb_addr_port_t *locals, u8 is_add,
1237                                      twice_nat_type_t twice_nat, u8 out2in_only,
1238                                      u8 *tag)
1239 {
1240   snat_main_t * sm = &snat_main;
1241   snat_static_mapping_t *m;
1242   snat_session_key_t m_key;
1243   clib_bihash_kv_8_8_t kv, value;
1244   snat_address_t *a = 0;
1245   int i;
1246   nat44_lb_addr_port_t *local;
1247   u32 elt_index, head_index, ses_index;
1248   snat_main_per_thread_data_t *tsm;
1249   snat_user_key_t u_key;
1250   snat_user_t *u;
1251   snat_session_t * s;
1252   dlist_elt_t * head, * elt;
1253   uword *bitmap = 0;
1254
1255   if (!sm->endpoint_dependent)
1256     return VNET_API_ERROR_FEATURE_DISABLED;
1257
1258   m_key.addr = e_addr;
1259   m_key.port = e_port;
1260   m_key.protocol = proto;
1261   m_key.fib_index = 0;
1262   kv.key = m_key.as_u64;
1263   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1264     m = 0;
1265   else
1266     m = pool_elt_at_index (sm->static_mappings, value.value);
1267
1268   if (is_add)
1269     {
1270       if (m)
1271         return VNET_API_ERROR_VALUE_EXIST;
1272
1273       if (vec_len (locals) < 2)
1274         return VNET_API_ERROR_INVALID_VALUE;
1275
1276       /* Find external address in allocated addresses and reserve port for
1277          address and port pair mapping when dynamic translations enabled */
1278       if (!(sm->static_mapping_only || out2in_only))
1279         {
1280           for (i = 0; i < vec_len (sm->addresses); i++)
1281             {
1282               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1283                 {
1284                   a = sm->addresses + i;
1285                   /* External port must be unused */
1286                   switch (proto)
1287                     {
1288 #define _(N, j, n, s) \
1289                     case SNAT_PROTOCOL_##N: \
1290                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1291                         return VNET_API_ERROR_INVALID_VALUE; \
1292                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1293                       if (e_port > 1024) \
1294                         { \
1295                           a->busy_##n##_ports++; \
1296                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
1297                         } \
1298                       break;
1299                       foreach_snat_protocol
1300 #undef _
1301                     default:
1302                       nat_log_info ("unknown protocol");
1303                       return VNET_API_ERROR_INVALID_VALUE_2;
1304                     }
1305                   break;
1306                 }
1307             }
1308           /* External address must be allocated */
1309           if (!a)
1310             return VNET_API_ERROR_NO_SUCH_ENTRY;
1311         }
1312
1313       pool_get (sm->static_mappings, m);
1314       memset (m, 0, sizeof (*m));
1315       m->tag = vec_dup (tag);
1316       m->external_addr = e_addr;
1317       m->addr_only = 0;
1318       m->external_port = e_port;
1319       m->proto = proto;
1320       m->twice_nat = twice_nat;
1321       m->out2in_only = out2in_only;
1322
1323       m_key.addr = m->external_addr;
1324       m_key.port = m->external_port;
1325       m_key.protocol = m->proto;
1326       m_key.fib_index = 0;
1327       kv.key = m_key.as_u64;
1328       kv.value = m - sm->static_mappings;
1329       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
1330         {
1331           nat_log_err ("static_mapping_by_external key add failed");
1332           return VNET_API_ERROR_UNSPECIFIED;
1333         }
1334
1335       m_key.fib_index = m->fib_index;
1336       for (i = 0; i < vec_len (locals); i++)
1337         {
1338           locals[i].fib_index = fib_table_find_or_create_and_lock (
1339             FIB_PROTOCOL_IP4, locals[i].vrf_id, FIB_SOURCE_PLUGIN_LOW);
1340           m_key.addr = locals[i].addr;
1341           m_key.fib_index = locals[i].fib_index;
1342           if (!out2in_only)
1343             {
1344               m_key.port = locals[i].port;
1345               kv.key = m_key.as_u64;
1346               kv.value = m - sm->static_mappings;
1347               clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
1348             }
1349           locals[i].prefix = (i == 0) ? locals[i].probability :\
1350             (locals[i - 1].prefix + locals[i].probability);
1351           vec_add1 (m->locals, locals[i]);
1352           if (sm->num_workers > 1)
1353             {
1354               ip4_header_t ip = {
1355                 .src_address = locals[i].addr,
1356               };
1357               bitmap = clib_bitmap_set (
1358                 bitmap, sm->worker_in2out_cb (&ip, m->fib_index), 1);
1359             }
1360         }
1361
1362       /* Assign workers */
1363       if (sm->num_workers > 1)
1364         {
1365           clib_bitmap_foreach (i, bitmap,
1366             ({
1367                vec_add1(m->workers, i);
1368             }));
1369         }
1370     }
1371   else
1372     {
1373       if (!m)
1374         return VNET_API_ERROR_NO_SUCH_ENTRY;
1375
1376       /* Free external address port */
1377       if (!(sm->static_mapping_only || out2in_only))
1378         {
1379           for (i = 0; i < vec_len (sm->addresses); i++)
1380             {
1381               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1382                 {
1383                   a = sm->addresses + i;
1384                   switch (proto)
1385                     {
1386 #define _(N, j, n, s) \
1387                     case SNAT_PROTOCOL_##N: \
1388                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1389                       if (e_port > 1024) \
1390                         { \
1391                           a->busy_##n##_ports--; \
1392                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
1393                         } \
1394                       break;
1395                       foreach_snat_protocol
1396 #undef _
1397                     default:
1398                       nat_log_info ("unknown protocol");
1399                       return VNET_API_ERROR_INVALID_VALUE_2;
1400                     }
1401                   break;
1402                 }
1403             }
1404         }
1405
1406       m_key.addr = m->external_addr;
1407       m_key.port = m->external_port;
1408       m_key.protocol = m->proto;
1409       m_key.fib_index = 0;
1410       kv.key = m_key.as_u64;
1411       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
1412         {
1413           nat_log_err ("static_mapping_by_external key del failed");
1414           return VNET_API_ERROR_UNSPECIFIED;
1415         }
1416
1417       vec_foreach (local, m->locals)
1418         {
1419           fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1420                             FIB_SOURCE_PLUGIN_LOW);
1421           m_key.addr = local->addr;
1422           if (!out2in_only)
1423             {
1424               m_key.port = local->port;
1425               m_key.fib_index = local->fib_index;
1426               kv.key = m_key.as_u64;
1427               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1428                 {
1429                   nat_log_err ("static_mapping_by_local key del failed");
1430                   return VNET_API_ERROR_UNSPECIFIED;
1431                 }
1432             }
1433
1434           if (sm->num_workers > 1)
1435             {
1436               ip4_header_t ip = {
1437                 .src_address = local->addr,
1438               };
1439               tsm = vec_elt_at_index (sm->per_thread_data,
1440                                       sm->worker_in2out_cb (&ip, m->fib_index));
1441             }
1442           else
1443             tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1444
1445           /* Delete sessions */
1446           u_key.addr = local->addr;
1447           u_key.fib_index = m->fib_index;
1448           kv.key = u_key.as_u64;
1449           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1450             {
1451               u = pool_elt_at_index (tsm->users, value.value);
1452               if (u->nstaticsessions)
1453                 {
1454                   head_index = u->sessions_per_user_list_head_index;
1455                   head = pool_elt_at_index (tsm->list_pool, head_index);
1456                   elt_index = head->next;
1457                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1458                   ses_index = elt->value;
1459                   while (ses_index != ~0)
1460                     {
1461                       s =  pool_elt_at_index (tsm->sessions, ses_index);
1462                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1463                       ses_index = elt->value;
1464
1465                       if (!(is_lb_session (s)))
1466                         continue;
1467
1468                       if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1469                           (clib_net_to_host_u16 (s->in2out.port) != local->port))
1470                         continue;
1471
1472                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1473                       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1474                     }
1475                 }
1476             }
1477         }
1478       vec_free(m->locals);
1479       vec_free(m->tag);
1480       vec_free(m->workers);
1481
1482       pool_put (sm->static_mappings, m);
1483     }
1484
1485   return 0;
1486 }
1487
1488 int
1489 snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
1490                   u8 twice_nat)
1491 {
1492   snat_address_t *a = 0;
1493   snat_session_t *ses;
1494   u32 *ses_to_be_removed = 0, *ses_index;
1495   snat_main_per_thread_data_t *tsm;
1496   snat_static_mapping_t *m;
1497   snat_interface_t *interface;
1498   int i;
1499   snat_address_t *addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
1500
1501   /* Find SNAT address */
1502   for (i=0; i < vec_len (addresses); i++)
1503     {
1504       if (addresses[i].addr.as_u32 == addr.as_u32)
1505         {
1506           a = addresses + i;
1507           break;
1508         }
1509     }
1510   if (!a)
1511     return VNET_API_ERROR_NO_SUCH_ENTRY;
1512
1513   if (delete_sm)
1514     {
1515       pool_foreach (m, sm->static_mappings,
1516       ({
1517           if (m->external_addr.as_u32 == addr.as_u32)
1518             (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1519                                             m->local_port, m->external_port,
1520                                             m->vrf_id, m->addr_only, ~0,
1521                                             m->proto, 0, m->twice_nat,
1522                                             m->out2in_only, m->tag);
1523       }));
1524     }
1525   else
1526     {
1527       /* Check if address is used in some static mapping */
1528       if (is_snat_address_used_in_static_mapping(sm, addr))
1529         {
1530           nat_log_notice ("address used in static mapping");
1531           return VNET_API_ERROR_UNSPECIFIED;
1532         }
1533     }
1534
1535   if (a->fib_index != ~0)
1536     fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4,
1537                      FIB_SOURCE_PLUGIN_LOW);
1538
1539   /* Delete sessions using address */
1540   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1541     {
1542       vec_foreach (tsm, sm->per_thread_data)
1543         {
1544           pool_foreach (ses, tsm->sessions, ({
1545             if (ses->out2in.addr.as_u32 == addr.as_u32)
1546               {
1547                 ses->outside_address_index = ~0;
1548                 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1549                 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1550               }
1551           }));
1552
1553           vec_foreach (ses_index, ses_to_be_removed)
1554             {
1555               ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1556               nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1557             }
1558
1559           vec_free (ses_to_be_removed);
1560        }
1561     }
1562
1563   if (twice_nat)
1564     {
1565       vec_del1 (sm->twice_nat_addresses, i);
1566       return 0;
1567     }
1568   else
1569     vec_del1 (sm->addresses, i);
1570
1571   /* Delete external address from FIB */
1572   pool_foreach (interface, sm->interfaces,
1573   ({
1574     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1575       continue;
1576
1577     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1578     break;
1579   }));
1580   pool_foreach (interface, sm->output_feature_interfaces,
1581   ({
1582     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1583       continue;
1584
1585     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1586     break;
1587   }));
1588
1589   return 0;
1590 }
1591
1592 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1593 {
1594   snat_main_t *sm = &snat_main;
1595   snat_interface_t *i;
1596   const char * feature_name, *del_feature_name;
1597   snat_address_t * ap;
1598   snat_static_mapping_t * m;
1599   snat_det_map_t * dm;
1600   nat_outside_fib_t *outside_fib;
1601   u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1602                                                        sw_if_index);
1603
1604   if (sm->out2in_dpo && !is_inside)
1605     return VNET_API_ERROR_UNSUPPORTED;
1606
1607   pool_foreach (i, sm->output_feature_interfaces,
1608   ({
1609     if (i->sw_if_index == sw_if_index)
1610       return VNET_API_ERROR_VALUE_EXIST;
1611   }));
1612
1613   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1614     feature_name = is_inside ?  "nat44-in2out-fast" : "nat44-out2in-fast";
1615   else
1616     {
1617       if (sm->num_workers > 1 && !sm->deterministic)
1618         feature_name = is_inside ?  "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1619       else if (sm->deterministic)
1620         feature_name = is_inside ?  "nat44-det-in2out" : "nat44-det-out2in";
1621       else if (sm->endpoint_dependent)
1622         feature_name = is_inside ?  "nat44-ed-in2out" : "nat44-ed-out2in";
1623       else
1624         feature_name = is_inside ?  "nat44-in2out" : "nat44-out2in";
1625     }
1626
1627   if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1628     sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index,
1629                                                       NAT_FQ_NELTS);
1630
1631   if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1632     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
1633                                                       NAT_FQ_NELTS);
1634
1635   if (!is_inside)
1636     {
1637       vec_foreach (outside_fib, sm->outside_fibs)
1638         {
1639           if (outside_fib->fib_index == fib_index)
1640             {
1641               if (is_del)
1642                 {
1643                   outside_fib->refcount--;
1644                   if (!outside_fib->refcount)
1645                     vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1646                 }
1647               else
1648                 outside_fib->refcount++;
1649               goto feature_set;
1650             }
1651         }
1652       if (!is_del)
1653         {
1654           vec_add2 (sm->outside_fibs, outside_fib, 1);
1655           outside_fib->refcount = 1;
1656           outside_fib->fib_index = fib_index;
1657         }
1658     }
1659 feature_set:
1660   pool_foreach (i, sm->interfaces,
1661   ({
1662     if (i->sw_if_index == sw_if_index)
1663       {
1664         if (is_del)
1665           {
1666             if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1667               {
1668                 if (is_inside)
1669                   i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1670                 else
1671                   i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1672
1673                 if (sm->num_workers > 1 && !sm->deterministic)
1674                   {
1675                     del_feature_name = "nat44-handoff-classify";
1676                     feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1677                                                  "nat44-out2in-worker-handoff";
1678                   }
1679                 else if (sm->deterministic)
1680                   {
1681                     del_feature_name = "nat44-det-classify";
1682                     feature_name = !is_inside ?  "nat44-det-in2out" :
1683                                                  "nat44-det-out2in";
1684                   }
1685                 else if (sm->endpoint_dependent)
1686                   {
1687                     del_feature_name = "nat44-ed-classify";
1688                     feature_name = !is_inside ?  "nat44-ed-in2out" :
1689                                                  "nat44-ed-out2in";
1690                   }
1691                 else
1692                   {
1693                     del_feature_name = "nat44-classify";
1694                     feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1695                   }
1696
1697                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1698                                              sw_if_index, 0, 0, 0);
1699                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1700                                              sw_if_index, 1, 0, 0);
1701                 if (!is_inside)
1702                   {
1703                     if (sm->endpoint_dependent)
1704                       vnet_feature_enable_disable ("ip4-local",
1705                                                    "nat44-ed-hairpinning",
1706                                                    sw_if_index, 1, 0, 0);
1707                     else
1708                       vnet_feature_enable_disable ("ip4-local",
1709                                                    "nat44-hairpinning",
1710                                                    sw_if_index, 1, 0, 0);
1711                   }
1712               }
1713             else
1714               {
1715                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1716                                              sw_if_index, 0, 0, 0);
1717                 pool_put (sm->interfaces, i);
1718                 if (is_inside)
1719                   {
1720                     if (sm->endpoint_dependent)
1721                       vnet_feature_enable_disable ("ip4-local",
1722                                                    "nat44-ed-hairpinning",
1723                                                    sw_if_index, 0, 0, 0);
1724                     else
1725                       vnet_feature_enable_disable ("ip4-local",
1726                                                    "nat44-hairpinning",
1727                                                    sw_if_index, 0, 0, 0);
1728                   }
1729               }
1730           }
1731         else
1732           {
1733             if ((nat_interface_is_inside(i) && is_inside) ||
1734                 (nat_interface_is_outside(i) && !is_inside))
1735               return 0;
1736
1737             if (sm->num_workers > 1 && !sm->deterministic)
1738               {
1739                 del_feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1740                                                  "nat44-out2in-worker-handoff";
1741                 feature_name = "nat44-handoff-classify";
1742               }
1743             else if (sm->deterministic)
1744               {
1745                 del_feature_name = !is_inside ?  "nat44-det-in2out" :
1746                                                  "nat44-det-out2in";
1747                 feature_name = "nat44-det-classify";
1748               }
1749             else if (sm->endpoint_dependent)
1750               {
1751                 del_feature_name = !is_inside ?  "nat44-ed-in2out" :
1752                                                  "nat44-ed-out2in";
1753                 feature_name = "nat44-ed-classify";
1754               }
1755             else
1756               {
1757                 del_feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1758                 feature_name = "nat44-classify";
1759               }
1760
1761             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1762                                          sw_if_index, 0, 0, 0);
1763             vnet_feature_enable_disable ("ip4-unicast", feature_name,
1764                                          sw_if_index, 1, 0, 0);
1765             if (!is_inside)
1766               {
1767                 if (sm->endpoint_dependent)
1768                   vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1769                                                sw_if_index, 0, 0, 0);
1770                 else
1771                   vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1772                                                sw_if_index, 0, 0, 0);
1773               }
1774             goto set_flags;
1775           }
1776
1777         goto fib;
1778       }
1779   }));
1780
1781   if (is_del)
1782     return VNET_API_ERROR_NO_SUCH_ENTRY;
1783
1784   pool_get (sm->interfaces, i);
1785   i->sw_if_index = sw_if_index;
1786   i->flags = 0;
1787   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1788
1789   if (is_inside && !sm->out2in_dpo)
1790     {
1791       if (sm->endpoint_dependent)
1792         vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1793                                      sw_if_index, 1, 0, 0);
1794       else
1795         vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1796                                      sw_if_index, 1, 0, 0);
1797     }
1798
1799 set_flags:
1800   if (is_inside)
1801     {
1802       i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1803       return 0;
1804     }
1805   else
1806     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1807
1808   /* Add/delete external addresses to FIB */
1809 fib:
1810   vec_foreach (ap, sm->addresses)
1811     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1812
1813   pool_foreach (m, sm->static_mappings,
1814   ({
1815     if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1816       continue;
1817
1818     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1819   }));
1820
1821   pool_foreach (dm, sm->det_maps,
1822   ({
1823     snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1824   }));
1825
1826   return 0;
1827 }
1828
1829 int snat_interface_add_del_output_feature (u32 sw_if_index,
1830                                            u8 is_inside,
1831                                            int is_del)
1832 {
1833   snat_main_t *sm = &snat_main;
1834   snat_interface_t *i;
1835   snat_address_t * ap;
1836   snat_static_mapping_t * m;
1837
1838   if (sm->deterministic ||
1839       (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1840     return VNET_API_ERROR_UNSUPPORTED;
1841
1842   pool_foreach (i, sm->interfaces,
1843   ({
1844     if (i->sw_if_index == sw_if_index)
1845       return VNET_API_ERROR_VALUE_EXIST;
1846   }));
1847
1848   if (is_inside)
1849     {
1850       if (sm->endpoint_dependent)
1851         {
1852           vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
1853                                        sw_if_index, !is_del, 0, 0);
1854           vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
1855                                        sw_if_index, !is_del, 0, 0);
1856         }
1857       else
1858         {
1859           vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1860                                        sw_if_index, !is_del, 0, 0);
1861           vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1862                                        sw_if_index, !is_del, 0, 0);
1863         }
1864       goto fq;
1865     }
1866
1867   if (sm->num_workers > 1)
1868     {
1869       vnet_feature_enable_disable ("ip4-unicast",
1870                                    "nat44-out2in-worker-handoff",
1871                                    sw_if_index, !is_del, 0, 0);
1872       vnet_feature_enable_disable ("ip4-output",
1873                                    "nat44-in2out-output-worker-handoff",
1874                                    sw_if_index, !is_del, 0, 0);
1875     }
1876   else
1877     {
1878       if (sm->endpoint_dependent)
1879         {
1880           vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-out2in",
1881                                        sw_if_index, !is_del, 0, 0);
1882           vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
1883                                        sw_if_index, !is_del, 0, 0);
1884         }
1885       else
1886         {
1887           vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
1888                                        sw_if_index, !is_del, 0, 0);
1889           vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1890                                        sw_if_index, !is_del, 0, 0);
1891         }
1892     }
1893
1894 fq:
1895   if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1896     sm->fq_in2out_output_index =
1897       vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1898
1899   if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1900     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1901
1902   pool_foreach (i, sm->output_feature_interfaces,
1903   ({
1904     if (i->sw_if_index == sw_if_index)
1905       {
1906         if (is_del)
1907           pool_put (sm->output_feature_interfaces, i);
1908         else
1909           return VNET_API_ERROR_VALUE_EXIST;
1910
1911         goto fib;
1912       }
1913   }));
1914
1915   if (is_del)
1916     return VNET_API_ERROR_NO_SUCH_ENTRY;
1917
1918   pool_get (sm->output_feature_interfaces, i);
1919   i->sw_if_index = sw_if_index;
1920   i->flags = 0;
1921   if (is_inside)
1922     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1923   else
1924     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1925
1926   /* Add/delete external addresses to FIB */
1927 fib:
1928   if (is_inside)
1929     return 0;
1930
1931   vec_foreach (ap, sm->addresses)
1932     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1933
1934   pool_foreach (m, sm->static_mappings,
1935   ({
1936     if (!(m->addr_only)  || (m->local_addr.as_u32 == m->external_addr.as_u32))
1937       continue;
1938
1939     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1940   }));
1941
1942   return 0;
1943 }
1944
1945 int snat_set_workers (uword * bitmap)
1946 {
1947   snat_main_t *sm = &snat_main;
1948   int i, j = 0;
1949
1950   if (sm->num_workers < 2)
1951     return VNET_API_ERROR_FEATURE_DISABLED;
1952
1953   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1954     return VNET_API_ERROR_INVALID_WORKER;
1955
1956   vec_free (sm->workers);
1957   clib_bitmap_foreach (i, bitmap,
1958     ({
1959       vec_add1(sm->workers, i);
1960       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
1961       j++;
1962     }));
1963
1964   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1965   sm->num_snat_thread = _vec_len (sm->workers);
1966
1967   return 0;
1968 }
1969
1970
1971 static void
1972 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1973                                        uword opaque,
1974                                        u32 sw_if_index,
1975                                        ip4_address_t * address,
1976                                        u32 address_length,
1977                                        u32 if_address_index,
1978                                        u32 is_delete);
1979
1980 static void
1981 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
1982                                  uword opaque,
1983                                  u32 sw_if_index,
1984                                  ip4_address_t * address,
1985                                  u32 address_length,
1986                                  u32 if_address_index,
1987                                  u32 is_delete);
1988
1989 static int
1990 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1991                                  u32 fib_index,
1992                                  u32 thread_index,
1993                                  snat_session_key_t * k,
1994                                  u32 * address_indexp,
1995                                  u16 port_per_thread,
1996                                  u32 snat_thread_index);
1997
1998 static clib_error_t * snat_init (vlib_main_t * vm)
1999 {
2000   snat_main_t * sm = &snat_main;
2001   clib_error_t * error = 0;
2002   ip4_main_t * im = &ip4_main;
2003   ip_lookup_main_t * lm = &im->lookup_main;
2004   uword *p;
2005   vlib_thread_registration_t *tr;
2006   vlib_thread_main_t *tm = vlib_get_thread_main ();
2007   uword *bitmap = 0;
2008   u32 i;
2009   ip4_add_del_interface_address_callback_t cb4;
2010   vlib_node_t * error_drop_node;
2011
2012   sm->vlib_main = vm;
2013   sm->vnet_main = vnet_get_main();
2014   sm->ip4_main = im;
2015   sm->ip4_lookup_main = lm;
2016   sm->api_main = &api_main;
2017   sm->first_worker_index = 0;
2018   sm->num_workers = 0;
2019   sm->num_snat_thread = 1;
2020   sm->workers = 0;
2021   sm->port_per_thread = 0xffff - 1024;
2022   sm->fq_in2out_index = ~0;
2023   sm->fq_out2in_index = ~0;
2024   sm->udp_timeout = SNAT_UDP_TIMEOUT;
2025   sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
2026   sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
2027   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
2028   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
2029   sm->forwarding_enabled = 0;
2030   sm->log_class = vlib_log_register_class ("nat", 0);
2031   error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2032   sm->error_node_index = error_drop_node->index;
2033
2034   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2035   if (p)
2036     {
2037       tr = (vlib_thread_registration_t *) p[0];
2038       if (tr)
2039         {
2040           sm->num_workers = tr->count;
2041           sm->first_worker_index = tr->first_index;
2042         }
2043     }
2044
2045   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2046
2047   /* Use all available workers by default */
2048   if (sm->num_workers > 1)
2049     {
2050       for (i=0; i < sm->num_workers; i++)
2051         bitmap = clib_bitmap_set (bitmap, i, 1);
2052       snat_set_workers(bitmap);
2053       clib_bitmap_free (bitmap);
2054     }
2055   else
2056     {
2057       sm->per_thread_data[0].snat_thread_index = 0;
2058     }
2059
2060   error = snat_api_init(vm, sm);
2061   if (error)
2062     return error;
2063
2064   /* Set up the interface address add/del callback */
2065   cb4.function = snat_ip4_add_del_interface_address_cb;
2066   cb4.function_opaque = 0;
2067
2068   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2069
2070   cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2071   cb4.function_opaque = 0;
2072
2073   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2074
2075   nat_dpo_module_init ();
2076
2077   /* Init IPFIX logging */
2078   snat_ipfix_logging_init(vm);
2079
2080   /* Init NAT64 */
2081   error = nat64_init(vm);
2082   if (error)
2083     return error;
2084
2085   dslite_init(vm);
2086
2087   nat66_init();
2088
2089   /* Init virtual fragmenentation reassembly */
2090   return nat_reass_init(vm);
2091 }
2092
2093 VLIB_INIT_FUNCTION (snat_init);
2094
2095 void snat_free_outside_address_and_port (snat_address_t * addresses,
2096                                          u32 thread_index,
2097                                          snat_session_key_t * k,
2098                                          u32 address_index)
2099 {
2100   snat_address_t *a;
2101   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2102
2103   ASSERT (address_index < vec_len (addresses));
2104
2105   a = addresses + address_index;
2106
2107   switch (k->protocol)
2108     {
2109 #define _(N, i, n, s) \
2110     case SNAT_PROTOCOL_##N: \
2111       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2112         port_host_byte_order) == 1); \
2113       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2114         port_host_byte_order, 0); \
2115       a->busy_##n##_ports--; \
2116       a->busy_##n##_ports_per_thread[thread_index]--; \
2117       break;
2118       foreach_snat_protocol
2119 #undef _
2120     default:
2121       nat_log_info ("unknown protocol");
2122       return;
2123     }
2124 }
2125
2126 /**
2127  * @brief Match NAT44 static mapping.
2128  *
2129  * @param sm          NAT main.
2130  * @param match       Address and port to match.
2131  * @param mapping     External or local address and port of the matched mapping.
2132  * @param by_external If 0 match by local address otherwise match by external
2133  *                    address.
2134  * @param is_addr_only If matched mapping is address only
2135  * @param twice_nat If matched mapping is twice NAT.
2136  * @param lb If matched mapping is load-balanced.
2137  *
2138  * @returns 0 if match found otherwise 1.
2139  */
2140 int snat_static_mapping_match (snat_main_t * sm,
2141                                snat_session_key_t match,
2142                                snat_session_key_t * mapping,
2143                                u8 by_external,
2144                                u8 *is_addr_only,
2145                                twice_nat_type_t *twice_nat,
2146                                u8 *lb)
2147 {
2148   clib_bihash_kv_8_8_t kv, value;
2149   snat_static_mapping_t *m;
2150   snat_session_key_t m_key;
2151   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2152   u32 rand, lo = 0, hi, mid;
2153
2154   m_key.fib_index = match.fib_index;
2155   if (by_external)
2156     {
2157       mapping_hash = &sm->static_mapping_by_external;
2158       m_key.fib_index = 0;
2159     }
2160
2161   m_key.addr = match.addr;
2162   m_key.port = clib_net_to_host_u16 (match.port);
2163   m_key.protocol = match.protocol;
2164
2165   kv.key = m_key.as_u64;
2166
2167   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2168     {
2169       /* Try address only mapping */
2170       m_key.port = 0;
2171       m_key.protocol = 0;
2172       kv.key = m_key.as_u64;
2173       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2174         return 1;
2175     }
2176
2177   m = pool_elt_at_index (sm->static_mappings, value.value);
2178
2179   if (by_external)
2180     {
2181       if (vec_len (m->locals))
2182         {
2183 get_local:
2184           hi = vec_len (m->locals) - 1;
2185           rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
2186           while (lo < hi)
2187             {
2188               mid = ((hi - lo) >> 1) + lo;
2189               (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
2190             }
2191           if (!(m->locals[lo].prefix >= rand))
2192             return 1;
2193           if (PREDICT_FALSE (sm->num_workers > 1))
2194             {
2195               ip4_header_t ip = {
2196                 .src_address = m->locals[lo].addr,
2197               };
2198               if (sm->worker_in2out_cb (&ip, m->fib_index) != vlib_get_thread_index ())
2199                 goto get_local;
2200             }
2201           mapping->addr = m->locals[lo].addr;
2202           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
2203           mapping->fib_index = m->locals[lo].fib_index;
2204         }
2205       else
2206         {
2207           mapping->fib_index = m->fib_index;
2208           mapping->addr = m->local_addr;
2209           /* Address only mapping doesn't change port */
2210           mapping->port = m->addr_only ? match.port
2211             : clib_host_to_net_u16 (m->local_port);
2212         }
2213       mapping->protocol = m->proto;
2214     }
2215   else
2216     {
2217       mapping->addr = m->external_addr;
2218       /* Address only mapping doesn't change port */
2219       mapping->port = m->addr_only ? match.port
2220         : clib_host_to_net_u16 (m->external_port);
2221       mapping->fib_index = sm->outside_fib_index;
2222     }
2223
2224   if (PREDICT_FALSE(is_addr_only != 0))
2225     *is_addr_only = m->addr_only;
2226
2227   if (PREDICT_FALSE(twice_nat != 0))
2228     *twice_nat = m->twice_nat;
2229
2230   if (PREDICT_FALSE(lb != 0))
2231     *lb = vec_len (m->locals) > 0;
2232
2233   return 0;
2234 }
2235
2236 static_always_inline u16
2237 snat_random_port (u16 min, u16 max)
2238 {
2239   snat_main_t *sm = &snat_main;
2240   return min + random_u32 (&sm->random_seed) /
2241     (random_u32_max() / (max - min + 1) + 1);
2242 }
2243
2244 int
2245 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2246                                      u32 fib_index,
2247                                      u32 thread_index,
2248                                      snat_session_key_t * k,
2249                                      u32 * address_indexp,
2250                                      u16 port_per_thread,
2251                                      u32 snat_thread_index)
2252 {
2253   snat_main_t *sm = &snat_main;
2254
2255   return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
2256                                  address_indexp, port_per_thread,
2257                                  snat_thread_index);
2258 }
2259
2260 static int
2261 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2262                                  u32 fib_index,
2263                                  u32 thread_index,
2264                                  snat_session_key_t * k,
2265                                  u32 * address_indexp,
2266                                  u16 port_per_thread,
2267                                  u32 snat_thread_index)
2268 {
2269   int i, gi = 0;
2270   snat_address_t *a, *ga = 0;
2271   u32 portnum;
2272
2273   for (i = 0; i < vec_len (addresses); i++)
2274     {
2275       a = addresses + i;
2276       switch (k->protocol)
2277         {
2278 #define _(N, j, n, s) \
2279         case SNAT_PROTOCOL_##N: \
2280           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2281             { \
2282               if (a->fib_index == fib_index) \
2283                 { \
2284                   while (1) \
2285                     { \
2286                       portnum = (port_per_thread * \
2287                         snat_thread_index) + \
2288                         snat_random_port(1, port_per_thread) + 1024; \
2289                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2290                         continue; \
2291                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2292                       a->busy_##n##_ports_per_thread[thread_index]++; \
2293                       a->busy_##n##_ports++; \
2294                       k->addr = a->addr; \
2295                       k->port = clib_host_to_net_u16(portnum); \
2296                       *address_indexp = i; \
2297                       return 0; \
2298                     } \
2299                 } \
2300               else if (a->fib_index == ~0) \
2301                 { \
2302                   ga = a; \
2303                   gi = i; \
2304                 } \
2305             } \
2306           break;
2307           foreach_snat_protocol
2308 #undef _
2309         default:
2310           nat_log_info ("unknown protocol");
2311           return 1;
2312         }
2313
2314     }
2315
2316   if (ga)
2317     {
2318       a = ga;
2319       switch (k->protocol)
2320         {
2321 #define _(N, j, n, s) \
2322         case SNAT_PROTOCOL_##N: \
2323           while (1) \
2324             { \
2325               portnum = (port_per_thread * \
2326                 snat_thread_index) + \
2327                 snat_random_port(1, port_per_thread) + 1024; \
2328               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2329                 continue; \
2330               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2331               a->busy_##n##_ports_per_thread[thread_index]++; \
2332               a->busy_##n##_ports++; \
2333               k->addr = a->addr; \
2334               k->port = clib_host_to_net_u16(portnum); \
2335               *address_indexp = gi; \
2336               return 0; \
2337             }
2338           break;
2339           foreach_snat_protocol
2340 #undef _
2341         default:
2342           nat_log_info ("unknown protocol");
2343           return 1;
2344         }
2345     }
2346
2347   /* Totally out of translations to use... */
2348   snat_ipfix_logging_addresses_exhausted(0);
2349   return 1;
2350 }
2351
2352 static int
2353 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2354                               u32 fib_index,
2355                               u32 thread_index,
2356                               snat_session_key_t * k,
2357                               u32 * address_indexp,
2358                               u16 port_per_thread,
2359                               u32 snat_thread_index)
2360 {
2361   snat_main_t *sm = &snat_main;
2362   snat_address_t *a = addresses;
2363   u16 m, ports, portnum, A, j;
2364   m = 16 - (sm->psid_offset + sm->psid_length);
2365   ports = (1 << (16 - sm->psid_length)) - (1 << m);
2366
2367   if (!vec_len (addresses))
2368     goto exhausted;
2369
2370   switch (k->protocol)
2371     {
2372 #define _(N, i, n, s) \
2373     case SNAT_PROTOCOL_##N: \
2374       if (a->busy_##n##_ports < ports) \
2375         { \
2376           while (1) \
2377             { \
2378               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2379               j = snat_random_port(0, pow2_mask(m)); \
2380               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2381               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2382                 continue; \
2383               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2384               a->busy_##n##_ports++; \
2385               k->addr = a->addr; \
2386               k->port = clib_host_to_net_u16 (portnum); \
2387               *address_indexp = i; \
2388               return 0; \
2389             } \
2390         } \
2391       break;
2392       foreach_snat_protocol
2393 #undef _
2394     default:
2395       nat_log_info ("unknown protocol");
2396       return 1;
2397     }
2398
2399 exhausted:
2400   /* Totally out of translations to use... */
2401   snat_ipfix_logging_addresses_exhausted(0);
2402   return 1;
2403 }
2404
2405 void
2406 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2407 {
2408   dpo_id_t dpo_v4 = DPO_INVALID;
2409   fib_prefix_t pfx = {
2410     .fp_proto = FIB_PROTOCOL_IP4,
2411     .fp_len = 32,
2412     .fp_addr.ip4.as_u32 = addr.as_u32,
2413   };
2414
2415   if (is_add)
2416     {
2417       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2418       fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
2419                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2420       dpo_reset (&dpo_v4);
2421     }
2422   else
2423     {
2424       fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2425     }
2426 }
2427
2428 uword
2429 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2430 {
2431   u32 *r = va_arg (*args, u32 *);
2432
2433   if (0);
2434 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2435   foreach_snat_protocol
2436 #undef _
2437   else
2438     return 0;
2439   return 1;
2440 }
2441
2442 u8 *
2443 format_snat_protocol (u8 * s, va_list * args)
2444 {
2445   u32 i = va_arg (*args, u32);
2446   u8 *t = 0;
2447
2448   switch (i)
2449     {
2450 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2451       foreach_snat_protocol
2452 #undef _
2453     default:
2454       s = format (s, "unknown");
2455       return s;
2456     }
2457   s = format (s, "%s", t);
2458   return s;
2459 }
2460
2461 u8 * format_snat_key (u8 * s, va_list * args);
2462
2463 u8 *
2464 format_session_kvp (u8 * s, va_list * args)
2465 {
2466   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2467   snat_session_key_t k;
2468
2469   k.as_u64 = v->key;
2470
2471   s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2472
2473   return s;
2474 }
2475
2476 u8 *
2477 format_static_mapping_kvp (u8 * s, va_list * args)
2478 {
2479   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2480   snat_session_key_t k;
2481
2482   k.as_u64 = v->key;
2483
2484   s = format (s, "%U static-mapping-index %llu", format_snat_key, &k, v->value);
2485
2486   return s;
2487 }
2488
2489 u8 *
2490 format_user_kvp (u8 * s, va_list * args)
2491 {
2492   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2493   snat_user_key_t k;
2494
2495   k.as_u64 = v->key;
2496
2497   s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
2498               k.fib_index, v->value);
2499
2500   return s;
2501 }
2502
2503 u8 *
2504 format_ed_session_kvp (u8 * s, va_list * args)
2505 {
2506   clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2507   nat_ed_ses_key_t k;
2508
2509   k.as_u64[0] = v->key[0];
2510   k.as_u64[1] = v->key[1];
2511
2512   s = format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2513               format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2514               format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2515               format_ip_protocol, k.proto, k.fib_index, v->value);
2516
2517   return s;
2518 }
2519
2520 static u32
2521 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2522 {
2523   snat_main_t *sm = &snat_main;
2524   u32 next_worker_index = 0;
2525   u32 hash;
2526
2527   next_worker_index = sm->first_worker_index;
2528   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2529          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2530
2531   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2532     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2533   else
2534     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2535
2536   return next_worker_index;
2537 }
2538
2539 static u32
2540 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2541 {
2542   snat_main_t *sm = &snat_main;
2543   udp_header_t *udp;
2544   u16 port;
2545   snat_session_key_t m_key;
2546   clib_bihash_kv_8_8_t kv, value;
2547   snat_static_mapping_t *m;
2548   u32 proto;
2549   u32 next_worker_index = 0;
2550
2551   /* first try static mappings without port */
2552   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2553     {
2554       m_key.addr = ip0->dst_address;
2555       m_key.port = 0;
2556       m_key.protocol = 0;
2557       m_key.fib_index = rx_fib_index0;
2558       kv.key = m_key.as_u64;
2559       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2560         {
2561           m = pool_elt_at_index (sm->static_mappings, value.value);
2562           return m->workers[0];
2563         }
2564     }
2565
2566   proto = ip_proto_to_snat_proto (ip0->protocol);
2567   udp = ip4_next_header (ip0);
2568   port = udp->dst_port;
2569
2570   if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2571     {
2572       if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2573         return vlib_get_thread_index ();
2574
2575       if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2576         {
2577           nat_reass_ip4_t *reass;
2578
2579           reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2580                                       ip0->fragment_id, ip0->protocol);
2581
2582           if (reass && (reass->thread_index != (u32) ~ 0))
2583             return reass->thread_index;
2584           else
2585             return vlib_get_thread_index ();
2586         }
2587     }
2588
2589   /* unknown protocol */
2590   if (PREDICT_FALSE (proto == ~0))
2591     {
2592       /* use current thread */
2593       return vlib_get_thread_index ();
2594     }
2595
2596   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2597     {
2598       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2599       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2600       if (!icmp_is_error_message (icmp))
2601         port = echo->identifier;
2602       else
2603         {
2604           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2605           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2606           void *l4_header = ip4_next_header (inner_ip);
2607           switch (proto)
2608             {
2609             case SNAT_PROTOCOL_ICMP:
2610               icmp = (icmp46_header_t*)l4_header;
2611               echo = (icmp_echo_header_t *)(icmp + 1);
2612               port = echo->identifier;
2613               break;
2614             case SNAT_PROTOCOL_UDP:
2615             case SNAT_PROTOCOL_TCP:
2616               port = ((tcp_udp_header_t*)l4_header)->src_port;
2617               break;
2618             default:
2619               return vlib_get_thread_index ();
2620             }
2621         }
2622     }
2623
2624   /* try static mappings with port */
2625   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2626     {
2627       m_key.addr = ip0->dst_address;
2628       m_key.port = clib_net_to_host_u16 (port);
2629       m_key.protocol = proto;
2630       m_key.fib_index = rx_fib_index0;
2631       kv.key = m_key.as_u64;
2632       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2633         {
2634           m = pool_elt_at_index (sm->static_mappings, value.value);
2635           return m->workers[0];
2636         }
2637     }
2638
2639   /* worker by outside port */
2640   next_worker_index = sm->first_worker_index;
2641   next_worker_index +=
2642     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2643   return next_worker_index;
2644 }
2645
2646 static u32
2647 nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index)
2648 {
2649   snat_main_t *sm = &snat_main;
2650   clib_bihash_kv_8_8_t kv, value;
2651   u32 proto, next_worker_index = 0;
2652   udp_header_t *udp;
2653   u16 port;
2654   snat_static_mapping_t *m;
2655   u32 hash;
2656
2657   /* first try static mappings without port */
2658   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2659     {
2660       make_sm_kv (&kv, &ip->dst_address, 0, rx_fib_index, 0);
2661       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2662         {
2663           m = pool_elt_at_index (sm->static_mappings, value.value);
2664           return m->workers[0];
2665         }
2666     }
2667
2668   proto = ip_proto_to_snat_proto (ip->protocol);
2669
2670   /* unknown protocol */
2671   if (PREDICT_FALSE (proto == ~0))
2672     {
2673       /* use current thread */
2674       return vlib_get_thread_index ();
2675     }
2676
2677   udp = ip4_next_header (ip);
2678   port = udp->dst_port;
2679
2680   if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
2681     {
2682       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2683       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2684       if (!icmp_is_error_message (icmp))
2685         port = echo->identifier;
2686       else
2687         {
2688           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2689           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2690           void *l4_header = ip4_next_header (inner_ip);
2691           switch (proto)
2692             {
2693             case SNAT_PROTOCOL_ICMP:
2694               icmp = (icmp46_header_t*)l4_header;
2695               echo = (icmp_echo_header_t *)(icmp + 1);
2696               port = echo->identifier;
2697               break;
2698             case SNAT_PROTOCOL_UDP:
2699             case SNAT_PROTOCOL_TCP:
2700               port = ((tcp_udp_header_t*)l4_header)->src_port;
2701               break;
2702             default:
2703               return vlib_get_thread_index ();
2704             }
2705         }
2706     }
2707
2708   /* try static mappings with port */
2709   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2710     {
2711       make_sm_kv (&kv, &ip->dst_address, proto, rx_fib_index,
2712                   clib_net_to_host_u16 (port));
2713       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2714         {
2715           m = pool_elt_at_index (sm->static_mappings, value.value);
2716           if (!vec_len(m->locals))
2717             return m->workers[0];
2718
2719           hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
2720                  (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >>24);
2721
2722           if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
2723             return m->workers[hash & (_vec_len (m->workers) - 1)];
2724           else
2725             return m->workers[hash % _vec_len (m->workers)];
2726         }
2727     }
2728
2729   /* worker by outside port */
2730   next_worker_index = sm->first_worker_index;
2731   next_worker_index +=
2732     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2733
2734   return next_worker_index;
2735 }
2736
2737 static clib_error_t *
2738 snat_config (vlib_main_t * vm, unformat_input_t * input)
2739 {
2740   snat_main_t * sm = &snat_main;
2741   nat66_main_t * nm = &nat66_main;
2742   u32 translation_buckets = 1024;
2743   u32 translation_memory_size = 128<<20;
2744   u32 user_buckets = 128;
2745   u32 user_memory_size = 64<<20;
2746   u32 max_translations_per_user = 100;
2747   u32 outside_vrf_id = 0;
2748   u32 outside_ip6_vrf_id = 0;
2749   u32 inside_vrf_id = 0;
2750   u32 static_mapping_buckets = 1024;
2751   u32 static_mapping_memory_size = 64<<20;
2752   u32 nat64_bib_buckets = 1024;
2753   u32 nat64_bib_memory_size = 128 << 20;
2754   u32 nat64_st_buckets = 2048;
2755   u32 nat64_st_memory_size = 256 << 20;
2756   u8 static_mapping_only = 0;
2757   u8 static_mapping_connection_tracking = 0;
2758   snat_main_per_thread_data_t *tsm;
2759   dslite_main_t * dm = &dslite_main;
2760
2761   sm->deterministic = 0;
2762   sm->out2in_dpo = 0;
2763   sm->endpoint_dependent = 0;
2764
2765   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2766     {
2767       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2768         ;
2769       else if (unformat (input, "translation hash memory %d",
2770                          &translation_memory_size));
2771       else if (unformat (input, "user hash buckets %d", &user_buckets))
2772         ;
2773       else if (unformat (input, "user hash memory %d",
2774                          &user_memory_size))
2775         ;
2776       else if (unformat (input, "max translations per user %d",
2777                          &max_translations_per_user))
2778         ;
2779       else if (unformat (input, "outside VRF id %d",
2780                          &outside_vrf_id))
2781         ;
2782       else if (unformat (input, "outside ip6 VRF id %d",
2783                          &outside_ip6_vrf_id))
2784         ;
2785       else if (unformat (input, "inside VRF id %d",
2786                          &inside_vrf_id))
2787         ;
2788       else if (unformat (input, "static mapping only"))
2789         {
2790           static_mapping_only = 1;
2791           if (unformat (input, "connection tracking"))
2792             static_mapping_connection_tracking = 1;
2793         }
2794       else if (unformat (input, "deterministic"))
2795         sm->deterministic = 1;
2796       else if (unformat (input, "nat64 bib hash buckets %d",
2797                          &nat64_bib_buckets))
2798         ;
2799       else if (unformat (input, "nat64 bib hash memory %d",
2800                          &nat64_bib_memory_size))
2801         ;
2802       else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2803         ;
2804       else if (unformat (input, "nat64 st hash memory %d",
2805                          &nat64_st_memory_size))
2806         ;
2807       else if (unformat (input, "out2in dpo"))
2808         sm->out2in_dpo = 1;
2809       else if (unformat (input, "dslite ce"))
2810         dslite_set_ce(dm, 1);
2811       else if (unformat (input, "endpoint-dependent"))
2812         sm->endpoint_dependent = 1;
2813       else
2814         return clib_error_return (0, "unknown input '%U'",
2815                                   format_unformat_error, input);
2816     }
2817
2818   /* for show commands, etc. */
2819   sm->translation_buckets = translation_buckets;
2820   sm->translation_memory_size = translation_memory_size;
2821   /* do not exceed load factor 10 */
2822   sm->max_translations = 10 * translation_buckets;
2823   sm->user_buckets = user_buckets;
2824   sm->user_memory_size = user_memory_size;
2825   sm->max_translations_per_user = max_translations_per_user;
2826   sm->outside_vrf_id = outside_vrf_id;
2827   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2828                                                              outside_vrf_id,
2829                                                              FIB_SOURCE_PLUGIN_HI);
2830   nm->outside_vrf_id = outside_ip6_vrf_id;
2831   nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2832                                                              outside_ip6_vrf_id,
2833                                                              FIB_SOURCE_PLUGIN_HI);
2834   sm->inside_vrf_id = inside_vrf_id;
2835   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2836                                                             inside_vrf_id,
2837                                                             FIB_SOURCE_PLUGIN_HI);
2838   sm->static_mapping_only = static_mapping_only;
2839   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2840
2841   nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2842                  nat64_st_memory_size);
2843
2844   if (sm->deterministic)
2845     {
2846       sm->in2out_node_index = snat_det_in2out_node.index;
2847       sm->in2out_output_node_index = ~0;
2848       sm->out2in_node_index = snat_det_out2in_node.index;
2849       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2850       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2851     }
2852   else
2853     {
2854       if (sm->endpoint_dependent)
2855         {
2856           sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2857           sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
2858           sm->in2out_node_index = nat44_ed_in2out_node.index;
2859           sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
2860           sm->out2in_node_index = nat44_ed_out2in_node.index;
2861           sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
2862           sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
2863         }
2864       else
2865         {
2866           sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2867           sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2868           sm->in2out_node_index = snat_in2out_node.index;
2869           sm->in2out_output_node_index = snat_in2out_output_node.index;
2870           sm->out2in_node_index = snat_out2in_node.index;
2871           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2872           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2873         }
2874       if (!static_mapping_only ||
2875           (static_mapping_only && static_mapping_connection_tracking))
2876         {
2877           vec_foreach (tsm, sm->per_thread_data)
2878             {
2879               if (sm->endpoint_dependent)
2880                 {
2881                   clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
2882                                          translation_buckets,
2883                                          translation_memory_size);
2884                   clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
2885                                                       format_ed_session_kvp);
2886
2887                   clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
2888                                          translation_buckets,
2889                                          translation_memory_size);
2890                   clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
2891                                                       format_ed_session_kvp);
2892                 }
2893               else
2894                 {
2895                   clib_bihash_init_8_8 (&tsm->in2out, "in2out",
2896                                         translation_buckets,
2897                                         translation_memory_size);
2898                   clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
2899                                                      format_session_kvp);
2900
2901                   clib_bihash_init_8_8 (&tsm->out2in, "out2in",
2902                                         translation_buckets,
2903                                         translation_memory_size);
2904                   clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
2905                                                      format_session_kvp);
2906                 }
2907
2908               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2909                                     user_memory_size);
2910               clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
2911                                                  format_user_kvp);
2912             }
2913
2914         }
2915       else
2916         {
2917           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2918           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2919         }
2920       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2921                             "static_mapping_by_local", static_mapping_buckets,
2922                             static_mapping_memory_size);
2923       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
2924                                          format_static_mapping_kvp);
2925
2926       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2927                             "static_mapping_by_external", static_mapping_buckets,
2928                             static_mapping_memory_size);
2929       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
2930                                          format_static_mapping_kvp);
2931     }
2932
2933   return 0;
2934 }
2935
2936 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2937
2938 u8 * format_snat_session_state (u8 * s, va_list * args)
2939 {
2940   u32 i = va_arg (*args, u32);
2941   u8 *t = 0;
2942
2943   switch (i)
2944     {
2945 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2946     foreach_snat_session_state
2947 #undef _
2948     default:
2949       t = format (t, "unknown");
2950     }
2951   s = format (s, "%s", t);
2952   return s;
2953 }
2954
2955 u8 * format_snat_key (u8 * s, va_list * args)
2956 {
2957   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2958
2959   s = format (s, "%U proto %U port %d fib %d",
2960               format_ip4_address, &key->addr,
2961               format_snat_protocol, key->protocol,
2962               clib_net_to_host_u16 (key->port), key->fib_index);
2963   return s;
2964 }
2965
2966 u8 * format_snat_session (u8 * s, va_list * args)
2967 {
2968   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2969   snat_session_t * sess = va_arg (*args, snat_session_t *);
2970
2971   if (snat_is_unk_proto_session (sess))
2972     {
2973       s = format (s, "  i2o %U proto %u fib %u\n",
2974                   format_ip4_address, &sess->in2out.addr,
2975                   clib_net_to_host_u16 (sess->in2out.port),
2976                   sess->in2out.fib_index);
2977       s = format (s, "    o2i %U proto %u fib %u\n",
2978                   format_ip4_address, &sess->out2in.addr,
2979                   clib_net_to_host_u16 (sess->out2in.port),
2980                   sess->out2in.fib_index);
2981     }
2982   else
2983     {
2984       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
2985       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
2986     }
2987   if (is_ed_session (sess) || is_fwd_bypass_session (sess))
2988     {
2989       if (is_twice_nat_session (sess))
2990         {
2991           s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
2992                       format_ip4_address, &sess->ext_host_addr,
2993                       clib_net_to_host_u16 (sess->ext_host_port),
2994                       format_ip4_address, &sess->ext_host_nat_addr,
2995                       clib_net_to_host_u16 (sess->ext_host_nat_port));
2996         }
2997       else
2998         {
2999           if (sess->ext_host_addr.as_u32)
3000               s = format (s, "       external host %U:%u\n",
3001                           format_ip4_address, &sess->ext_host_addr,
3002                           clib_net_to_host_u16 (sess->ext_host_port));
3003         }
3004     }
3005   s = format (s, "       index %llu\n", sess - sm->sessions);
3006   s = format (s, "       last heard %.2f\n", sess->last_heard);
3007   s = format (s, "       total pkts %d, total bytes %lld\n",
3008               sess->total_pkts, sess->total_bytes);
3009   if (snat_is_session_static (sess))
3010     s = format (s, "       static translation\n");
3011   else
3012     s = format (s, "       dynamic translation\n");
3013   if (is_fwd_bypass_session (sess))
3014     s = format (s, "       forwarding-bypass\n");
3015   if (is_lb_session (sess))
3016     s = format (s, "       load-balancing\n");
3017   if (is_twice_nat_session (sess))
3018     s = format (s, "       twice-nat\n");
3019
3020   return s;
3021 }
3022
3023 u8 * format_snat_user (u8 * s, va_list * args)
3024 {
3025   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
3026   snat_user_t * u = va_arg (*args, snat_user_t *);
3027   int verbose = va_arg (*args, int);
3028   dlist_elt_t * head, * elt;
3029   u32 elt_index, head_index;
3030   u32 session_index;
3031   snat_session_t * sess;
3032
3033   s = format (s, "%U: %d dynamic translations, %d static translations\n",
3034               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
3035
3036   if (verbose == 0)
3037     return s;
3038
3039   if (u->nsessions || u->nstaticsessions)
3040     {
3041       head_index = u->sessions_per_user_list_head_index;
3042       head = pool_elt_at_index (sm->list_pool, head_index);
3043
3044       elt_index = head->next;
3045       elt = pool_elt_at_index (sm->list_pool, elt_index);
3046       session_index = elt->value;
3047
3048       while (session_index != ~0)
3049         {
3050           sess = pool_elt_at_index (sm->sessions, session_index);
3051
3052           s = format (s, "  %U\n", format_snat_session, sm, sess);
3053
3054           elt_index = elt->next;
3055           elt = pool_elt_at_index (sm->list_pool, elt_index);
3056           session_index = elt->value;
3057         }
3058     }
3059
3060   return s;
3061 }
3062
3063 u8 * format_snat_static_mapping (u8 * s, va_list * args)
3064 {
3065   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
3066   nat44_lb_addr_port_t *local;
3067
3068   if (m->addr_only)
3069       s = format (s, "local %U external %U vrf %d %s %s",
3070                   format_ip4_address, &m->local_addr,
3071                   format_ip4_address, &m->external_addr,
3072                   m->vrf_id,
3073                   m->twice_nat == TWICE_NAT ? "twice-nat" :
3074                   m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
3075                   m->out2in_only ? "out2in-only" : "");
3076   else
3077    {
3078       if (vec_len (m->locals))
3079         {
3080           s = format (s, "%U external %U:%d %s %s",
3081                       format_snat_protocol, m->proto,
3082                       format_ip4_address, &m->external_addr, m->external_port,
3083                       m->twice_nat == TWICE_NAT ? "twice-nat" :
3084                       m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
3085                       m->out2in_only ? "out2in-only" : "");
3086           vec_foreach (local, m->locals)
3087             s = format (s, "\n  local %U:%d vrf %d probability %d\%",
3088                         format_ip4_address, &local->addr, local->port,
3089                         local->vrf_id, local->probability);
3090         }
3091       else
3092         s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
3093                     format_snat_protocol, m->proto,
3094                     format_ip4_address, &m->local_addr, m->local_port,
3095                     format_ip4_address, &m->external_addr, m->external_port,
3096                     m->vrf_id,
3097                     m->twice_nat == TWICE_NAT ? "twice-nat" :
3098                     m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
3099                     m->out2in_only ? "out2in-only" : "");
3100    }
3101   return s;
3102 }
3103
3104 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
3105 {
3106   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
3107   vnet_main_t *vnm = vnet_get_main();
3108
3109   if (m->addr_only)
3110       s = format (s, "local %U external %U vrf %d",
3111                   format_ip4_address, &m->l_addr,
3112                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
3113                   m->vrf_id);
3114   else
3115       s = format (s, "%U local %U:%d external %U:%d vrf %d",
3116                   format_snat_protocol, m->proto,
3117                   format_ip4_address, &m->l_addr, m->l_port,
3118                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
3119                   m->e_port, m->vrf_id);
3120
3121   return s;
3122 }
3123
3124 u8 * format_det_map_ses (u8 * s, va_list * args)
3125 {
3126   snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
3127   ip4_address_t in_addr, out_addr;
3128   u32 in_offset, out_offset;
3129   snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
3130   u32 * i = va_arg (*args, u32 *);
3131
3132   u32 user_index = *i / SNAT_DET_SES_PER_USER;
3133   in_addr.as_u32 = clib_host_to_net_u32 (
3134     clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
3135   in_offset = clib_net_to_host_u32(in_addr.as_u32) -
3136     clib_net_to_host_u32(det_map->in_addr.as_u32);
3137   out_offset = in_offset / det_map->sharing_ratio;
3138   out_addr.as_u32 = clib_host_to_net_u32(
3139     clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
3140   s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
3141               format_ip4_address, &in_addr,
3142               clib_net_to_host_u16 (ses->in_port),
3143               format_ip4_address, &out_addr,
3144               clib_net_to_host_u16 (ses->out.out_port),
3145               format_ip4_address, &ses->out.ext_host_addr,
3146               clib_net_to_host_u16 (ses->out.ext_host_port),
3147               format_snat_session_state, ses->state,
3148               ses->expire);
3149
3150   return s;
3151 }
3152
3153 static void
3154 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
3155                                  uword opaque,
3156                                  u32 sw_if_index,
3157                                  ip4_address_t * address,
3158                                  u32 address_length,
3159                                  u32 if_address_index,
3160                                  u32 is_delete)
3161 {
3162   snat_main_t *sm = &snat_main;
3163   snat_static_map_resolve_t *rp;
3164   snat_static_mapping_t *m;
3165   snat_session_key_t m_key;
3166   clib_bihash_kv_8_8_t kv, value;
3167   int i, rv;
3168   ip4_address_t l_addr;
3169
3170   for (i = 0; i < vec_len (sm->to_resolve); i++)
3171     {
3172       rp = sm->to_resolve + i;
3173       if (rp->addr_only == 0)
3174         continue;
3175       if (rp->sw_if_index == sw_if_index)
3176         goto match;
3177     }
3178
3179   return;
3180
3181 match:
3182   m_key.addr.as_u32 = address->as_u32;
3183   m_key.port = rp->addr_only ? 0 : rp->e_port;
3184   m_key.protocol = rp->addr_only ? 0 : rp->proto;
3185   m_key.fib_index = sm->outside_fib_index;
3186   kv.key = m_key.as_u64;
3187   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
3188     m = 0;
3189   else
3190     m = pool_elt_at_index (sm->static_mappings, value.value);
3191
3192   if (!is_delete)
3193     {
3194       /* Don't trip over lease renewal, static config */
3195       if (m)
3196         return;
3197     }
3198   else
3199     {
3200       if (!m)
3201         return;
3202     }
3203
3204   /* Indetity mapping? */
3205   if (rp->l_addr.as_u32 == 0)
3206     l_addr.as_u32 = address[0].as_u32;
3207   else
3208     l_addr.as_u32 = rp->l_addr.as_u32;
3209   /* Add the static mapping */
3210   rv = snat_add_static_mapping (l_addr,
3211                                 address[0],
3212                                 rp->l_port,
3213                                 rp->e_port,
3214                                 rp->vrf_id,
3215                                 rp->addr_only,
3216                                 ~0 /* sw_if_index */,
3217                                 rp->proto,
3218                                 !is_delete,
3219                                 0, 0, rp->tag);
3220   if (rv)
3221     nat_log_notice ("snat_add_static_mapping returned %d", rv);
3222 }
3223
3224 static void
3225 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3226                                        uword opaque,
3227                                        u32 sw_if_index,
3228                                        ip4_address_t * address,
3229                                        u32 address_length,
3230                                        u32 if_address_index,
3231                                        u32 is_delete)
3232 {
3233   snat_main_t *sm = &snat_main;
3234   snat_static_map_resolve_t *rp;
3235   ip4_address_t l_addr;
3236   int i, j;
3237   int rv;
3238   u8 twice_nat = 0;
3239   snat_address_t *addresses = sm->addresses;
3240
3241   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3242     {
3243       if (sw_if_index == sm->auto_add_sw_if_indices[i])
3244           goto match;
3245     }
3246
3247   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
3248     {
3249       twice_nat = 1;
3250       addresses = sm->twice_nat_addresses;
3251       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3252           goto match;
3253     }
3254
3255   return;
3256
3257 match:
3258   if (!is_delete)
3259     {
3260       /* Don't trip over lease renewal, static config */
3261       for (j = 0; j < vec_len(addresses); j++)
3262         if (addresses[j].addr.as_u32 == address->as_u32)
3263           return;
3264
3265       (void) snat_add_address (sm, address, ~0, twice_nat);
3266       /* Scan static map resolution vector */
3267       for (j = 0; j < vec_len (sm->to_resolve); j++)
3268         {
3269           rp = sm->to_resolve + j;
3270           if (rp->addr_only)
3271             continue;
3272           /* On this interface? */
3273           if (rp->sw_if_index == sw_if_index)
3274             {
3275               /* Indetity mapping? */
3276               if (rp->l_addr.as_u32 == 0)
3277                 l_addr.as_u32 = address[0].as_u32;
3278               else
3279                 l_addr.as_u32 = rp->l_addr.as_u32;
3280               /* Add the static mapping */
3281               rv = snat_add_static_mapping (l_addr,
3282                                             address[0],
3283                                             rp->l_port,
3284                                             rp->e_port,
3285                                             rp->vrf_id,
3286                                             rp->addr_only,
3287                                             ~0 /* sw_if_index */,
3288                                             rp->proto,
3289                                             rp->is_add,
3290                                             0, 0, rp->tag);
3291               if (rv)
3292                 nat_log_notice ("snat_add_static_mapping returned %d", rv);
3293             }
3294         }
3295       return;
3296     }
3297   else
3298     {
3299       (void) snat_del_address(sm, address[0], 1, twice_nat);
3300       return;
3301     }
3302 }
3303
3304
3305 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
3306                                 u8 twice_nat)
3307 {
3308   ip4_main_t * ip4_main = sm->ip4_main;
3309   ip4_address_t * first_int_addr;
3310   snat_static_map_resolve_t *rp;
3311   u32 *indices_to_delete = 0;
3312   int i, j;
3313   u32 *auto_add_sw_if_indices =
3314     twice_nat ? sm->auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3315
3316   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3317                                                 0 /* just want the address*/);
3318
3319   for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
3320     {
3321       if (auto_add_sw_if_indices[i] == sw_if_index)
3322         {
3323           if (is_del)
3324             {
3325               /* if have address remove it */
3326               if (first_int_addr)
3327                   (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3328               else
3329                 {
3330                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3331                     {
3332                       rp = sm->to_resolve + j;
3333                       if (rp->sw_if_index == sw_if_index)
3334                         vec_add1 (indices_to_delete, j);
3335                     }
3336                   if (vec_len(indices_to_delete))
3337                     {
3338                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3339                         vec_del1(sm->to_resolve, j);
3340                       vec_free(indices_to_delete);
3341                     }
3342                 }
3343               if (twice_nat)
3344                 vec_del1(sm->auto_add_sw_if_indices_twice_nat, i);
3345               else
3346                 vec_del1(sm->auto_add_sw_if_indices, i);
3347             }
3348           else
3349             return VNET_API_ERROR_VALUE_EXIST;
3350
3351           return 0;
3352         }
3353     }
3354
3355   if (is_del)
3356     return VNET_API_ERROR_NO_SUCH_ENTRY;
3357
3358   /* add to the auto-address list */
3359   if (twice_nat)
3360     vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3361   else
3362     vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3363
3364   /* If the address is already bound - or static - add it now */
3365   if (first_int_addr)
3366       (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
3367
3368   return 0;
3369 }
3370
3371 int
3372 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3373                    snat_protocol_t proto, u32 vrf_id, int is_in)
3374 {
3375   snat_main_per_thread_data_t *tsm;
3376   clib_bihash_kv_8_8_t kv, value;
3377   ip4_header_t ip;
3378   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3379   snat_session_key_t key;
3380   snat_session_t *s;
3381   clib_bihash_8_8_t *t;
3382
3383   if (sm->endpoint_dependent)
3384     return VNET_API_ERROR_UNSUPPORTED;
3385
3386   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3387   if (sm->num_workers > 1)
3388     tsm =
3389       vec_elt_at_index (sm->per_thread_data,
3390                         sm->worker_in2out_cb (&ip, fib_index));
3391   else
3392     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3393
3394   key.addr.as_u32 = addr->as_u32;
3395   key.port = clib_host_to_net_u16 (port);
3396   key.protocol = proto;
3397   key.fib_index = fib_index;
3398   kv.key = key.as_u64;
3399   t = is_in ? &tsm->in2out : &tsm->out2in;
3400   if (!clib_bihash_search_8_8 (t, &kv, &value))
3401     {
3402       if (pool_is_free_index (tsm->sessions, value.value))
3403         return VNET_API_ERROR_UNSPECIFIED;
3404
3405       s = pool_elt_at_index (tsm->sessions, value.value);
3406       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3407       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3408       return 0;
3409     }
3410
3411   return VNET_API_ERROR_NO_SUCH_ENTRY;
3412 }
3413
3414 int
3415 nat44_del_ed_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3416                       ip4_address_t *eh_addr, u16 eh_port, u8 proto,
3417                       u32 vrf_id, int is_in)
3418 {
3419   ip4_header_t ip;
3420   clib_bihash_16_8_t *t;
3421   nat_ed_ses_key_t key;
3422   clib_bihash_kv_16_8_t kv, value;
3423   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3424   snat_session_t *s;
3425   snat_main_per_thread_data_t *tsm;
3426
3427   if (!sm->endpoint_dependent)
3428     return VNET_API_ERROR_FEATURE_DISABLED;
3429
3430   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3431   if (sm->num_workers > 1)
3432     tsm =
3433       vec_elt_at_index (sm->per_thread_data,
3434                         sm->worker_in2out_cb (&ip, fib_index));
3435   else
3436     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3437
3438   t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
3439   key.l_addr.as_u32 = addr->as_u32;
3440   key.r_addr.as_u32 = eh_addr->as_u32;
3441   key.l_port = clib_host_to_net_u16 (port);
3442   key.r_port = clib_host_to_net_u16 (eh_port);
3443   key.proto = proto;
3444   key.fib_index = clib_host_to_net_u32 (fib_index);
3445   kv.key[0] = key.as_u64[0];
3446   kv.key[1] = key.as_u64[1];
3447   if (clib_bihash_search_16_8 (t, &kv, &value))
3448     return VNET_API_ERROR_NO_SUCH_ENTRY;
3449
3450   if (pool_is_free_index (tsm->sessions, value.value))
3451     return VNET_API_ERROR_UNSPECIFIED;
3452   s = pool_elt_at_index (tsm->sessions, value.value);
3453   nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3454   nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3455   return 0;
3456 }
3457
3458 void
3459 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
3460 {
3461   snat_main_t *sm = &snat_main;
3462
3463   sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3464   sm->psid = psid;
3465   sm->psid_offset = psid_offset;
3466   sm->psid_length = psid_length;
3467 }
3468
3469 void
3470 nat_set_alloc_addr_and_port_default (void)
3471 {
3472   snat_main_t *sm = &snat_main;
3473
3474   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3475 }
3476