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