NAT44: one-armed NAT and identity mapping (VPP-1212)
[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               }
1633             else
1634               {
1635                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1636                                              sw_if_index, 0, 0, 0);
1637                 pool_put (sm->interfaces, i);
1638               }
1639           }
1640         else
1641           {
1642             if ((nat_interface_is_inside(i) && is_inside) ||
1643                 (nat_interface_is_outside(i) && !is_inside))
1644               return 0;
1645
1646             if (sm->num_workers > 1 && !sm->deterministic)
1647               {
1648                 del_feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1649                                                  "nat44-out2in-worker-handoff";
1650                 feature_name = "nat44-handoff-classify";
1651               }
1652             else if (sm->deterministic)
1653               {
1654                 del_feature_name = !is_inside ?  "nat44-det-in2out" :
1655                                                  "nat44-det-out2in";
1656                 feature_name = "nat44-det-classify";
1657               }
1658             else
1659               {
1660                 del_feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1661                 feature_name = "nat44-classify";
1662               }
1663
1664             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1665                                          sw_if_index, 0, 0, 0);
1666             vnet_feature_enable_disable ("ip4-unicast", feature_name,
1667                                          sw_if_index, 1, 0, 0);
1668             goto set_flags;
1669           }
1670
1671         goto fib;
1672       }
1673   }));
1674
1675   if (is_del)
1676     return VNET_API_ERROR_NO_SUCH_ENTRY;
1677
1678   pool_get (sm->interfaces, i);
1679   i->sw_if_index = sw_if_index;
1680   i->flags = 0;
1681   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1682
1683 set_flags:
1684   if (is_inside)
1685     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1686   else
1687     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1688
1689   /* Add/delete external addresses to FIB */
1690 fib:
1691   if (is_inside && !sm->out2in_dpo)
1692     {
1693       vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1694                                    sw_if_index, !is_del, 0, 0);
1695       return 0;
1696     }
1697
1698   vec_foreach (ap, sm->addresses)
1699     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1700
1701   pool_foreach (m, sm->static_mappings,
1702   ({
1703     if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1704       continue;
1705
1706     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1707   }));
1708
1709   pool_foreach (dm, sm->det_maps,
1710   ({
1711     snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1712   }));
1713
1714   return 0;
1715 }
1716
1717 int snat_interface_add_del_output_feature (u32 sw_if_index,
1718                                            u8 is_inside,
1719                                            int is_del)
1720 {
1721   snat_main_t *sm = &snat_main;
1722   snat_interface_t *i;
1723   snat_address_t * ap;
1724   snat_static_mapping_t * m;
1725
1726   if (sm->deterministic ||
1727       (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1728     return VNET_API_ERROR_UNSUPPORTED;
1729
1730   pool_foreach (i, sm->interfaces,
1731   ({
1732     if (i->sw_if_index == sw_if_index)
1733       return VNET_API_ERROR_VALUE_EXIST;
1734   }));
1735
1736   if (is_inside)
1737     {
1738       vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1739                                    sw_if_index, !is_del, 0, 0);
1740       vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1741                                    sw_if_index, !is_del, 0, 0);
1742       goto fq;
1743     }
1744
1745   if (sm->num_workers > 1)
1746     {
1747       vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1748                                    sw_if_index, !is_del, 0, 0);
1749       vnet_feature_enable_disable ("ip4-output",
1750                                    "nat44-in2out-output-worker-handoff",
1751                                    sw_if_index, !is_del, 0, 0);
1752     }
1753   else
1754     {
1755       vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1756                                    !is_del, 0, 0);
1757       vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1758                                    sw_if_index, !is_del, 0, 0);
1759     }
1760
1761 fq:
1762   if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1763     sm->fq_in2out_output_index =
1764       vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1765
1766   if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1767     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1768
1769   pool_foreach (i, sm->output_feature_interfaces,
1770   ({
1771     if (i->sw_if_index == sw_if_index)
1772       {
1773         if (is_del)
1774           pool_put (sm->output_feature_interfaces, i);
1775         else
1776           return VNET_API_ERROR_VALUE_EXIST;
1777
1778         goto fib;
1779       }
1780   }));
1781
1782   if (is_del)
1783     return VNET_API_ERROR_NO_SUCH_ENTRY;
1784
1785   pool_get (sm->output_feature_interfaces, i);
1786   i->sw_if_index = sw_if_index;
1787   i->flags = 0;
1788   if (is_inside)
1789     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1790   else
1791     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1792
1793   /* Add/delete external addresses to FIB */
1794 fib:
1795   if (is_inside)
1796     return 0;
1797
1798   vec_foreach (ap, sm->addresses)
1799     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1800
1801   pool_foreach (m, sm->static_mappings,
1802   ({
1803     if (!(m->addr_only)  || (m->local_addr.as_u32 == m->external_addr.as_u32))
1804       continue;
1805
1806     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1807   }));
1808
1809   return 0;
1810 }
1811
1812 int snat_set_workers (uword * bitmap)
1813 {
1814   snat_main_t *sm = &snat_main;
1815   int i, j = 0;
1816
1817   if (sm->num_workers < 2)
1818     return VNET_API_ERROR_FEATURE_DISABLED;
1819
1820   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1821     return VNET_API_ERROR_INVALID_WORKER;
1822
1823   vec_free (sm->workers);
1824   clib_bitmap_foreach (i, bitmap,
1825     ({
1826       vec_add1(sm->workers, i);
1827       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
1828       j++;
1829     }));
1830
1831   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1832   sm->num_snat_thread = _vec_len (sm->workers);
1833
1834   return 0;
1835 }
1836
1837
1838 static void
1839 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1840                                        uword opaque,
1841                                        u32 sw_if_index,
1842                                        ip4_address_t * address,
1843                                        u32 address_length,
1844                                        u32 if_address_index,
1845                                        u32 is_delete);
1846
1847 static void
1848 nat_ip4_add_del_addr_only_sm_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 int
1857 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1858                                  u32 fib_index,
1859                                  u32 thread_index,
1860                                  snat_session_key_t * k,
1861                                  u32 * address_indexp,
1862                                  u16 port_per_thread,
1863                                  u32 snat_thread_index);
1864
1865 static clib_error_t * snat_init (vlib_main_t * vm)
1866 {
1867   snat_main_t * sm = &snat_main;
1868   clib_error_t * error = 0;
1869   ip4_main_t * im = &ip4_main;
1870   ip_lookup_main_t * lm = &im->lookup_main;
1871   uword *p;
1872   vlib_thread_registration_t *tr;
1873   vlib_thread_main_t *tm = vlib_get_thread_main ();
1874   uword *bitmap = 0;
1875   u32 i;
1876   ip4_add_del_interface_address_callback_t cb4;
1877
1878   sm->vlib_main = vm;
1879   sm->vnet_main = vnet_get_main();
1880   sm->ip4_main = im;
1881   sm->ip4_lookup_main = lm;
1882   sm->api_main = &api_main;
1883   sm->first_worker_index = 0;
1884   sm->next_worker = 0;
1885   sm->num_workers = 0;
1886   sm->num_snat_thread = 1;
1887   sm->workers = 0;
1888   sm->port_per_thread = 0xffff - 1024;
1889   sm->fq_in2out_index = ~0;
1890   sm->fq_out2in_index = ~0;
1891   sm->udp_timeout = SNAT_UDP_TIMEOUT;
1892   sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1893   sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1894   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1895   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
1896   sm->forwarding_enabled = 0;
1897
1898   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1899   if (p)
1900     {
1901       tr = (vlib_thread_registration_t *) p[0];
1902       if (tr)
1903         {
1904           sm->num_workers = tr->count;
1905           sm->first_worker_index = tr->first_index;
1906         }
1907     }
1908
1909   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1910
1911   /* Use all available workers by default */
1912   if (sm->num_workers > 1)
1913     {
1914       for (i=0; i < sm->num_workers; i++)
1915         bitmap = clib_bitmap_set (bitmap, i, 1);
1916       snat_set_workers(bitmap);
1917       clib_bitmap_free (bitmap);
1918     }
1919   else
1920     {
1921       sm->per_thread_data[0].snat_thread_index = 0;
1922     }
1923
1924   error = snat_api_init(vm, sm);
1925   if (error)
1926     return error;
1927
1928   /* Set up the interface address add/del callback */
1929   cb4.function = snat_ip4_add_del_interface_address_cb;
1930   cb4.function_opaque = 0;
1931
1932   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1933
1934   cb4.function = nat_ip4_add_del_addr_only_sm_cb;
1935   cb4.function_opaque = 0;
1936
1937   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1938
1939   nat_dpo_module_init ();
1940
1941   /* Init IPFIX logging */
1942   snat_ipfix_logging_init(vm);
1943
1944   /* Init NAT64 */
1945   error = nat64_init(vm);
1946   if (error)
1947     return error;
1948
1949   dslite_init(vm);
1950
1951   nat66_init();
1952
1953   /* Init virtual fragmenentation reassembly */
1954   return nat_reass_init(vm);
1955 }
1956
1957 VLIB_INIT_FUNCTION (snat_init);
1958
1959 void snat_free_outside_address_and_port (snat_address_t * addresses,
1960                                          u32 thread_index,
1961                                          snat_session_key_t * k,
1962                                          u32 address_index)
1963 {
1964   snat_address_t *a;
1965   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1966
1967   ASSERT (address_index < vec_len (addresses));
1968
1969   a = addresses + address_index;
1970
1971   switch (k->protocol)
1972     {
1973 #define _(N, i, n, s) \
1974     case SNAT_PROTOCOL_##N: \
1975       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1976         port_host_byte_order) == 1); \
1977       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1978         port_host_byte_order, 0); \
1979       a->busy_##n##_ports--; \
1980       a->busy_##n##_ports_per_thread[thread_index]--; \
1981       break;
1982       foreach_snat_protocol
1983 #undef _
1984     default:
1985       clib_warning("unknown_protocol");
1986       return;
1987     }
1988 }
1989
1990 /**
1991  * @brief Match NAT44 static mapping.
1992  *
1993  * @param sm          NAT main.
1994  * @param match       Address and port to match.
1995  * @param mapping     External or local address and port of the matched mapping.
1996  * @param by_external If 0 match by local address otherwise match by external
1997  *                    address.
1998  * @param is_addr_only If matched mapping is address only
1999  * @param twice_nat If matched mapping is twice NAT.
2000  * @param lb If matched mapping is load-balanced.
2001  *
2002  * @returns 0 if match found otherwise 1.
2003  */
2004 int snat_static_mapping_match (snat_main_t * sm,
2005                                snat_session_key_t match,
2006                                snat_session_key_t * mapping,
2007                                u8 by_external,
2008                                u8 *is_addr_only,
2009                                twice_nat_type_t *twice_nat,
2010                                u8 *lb)
2011 {
2012   clib_bihash_kv_8_8_t kv, value;
2013   snat_static_mapping_t *m;
2014   snat_session_key_t m_key;
2015   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2016   u32 rand, lo = 0, hi, mid;
2017
2018   if (by_external)
2019     mapping_hash = &sm->static_mapping_by_external;
2020
2021   m_key.addr = match.addr;
2022   m_key.port = clib_net_to_host_u16 (match.port);
2023   m_key.protocol = match.protocol;
2024   m_key.fib_index = match.fib_index;
2025
2026   kv.key = m_key.as_u64;
2027
2028   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2029     {
2030       /* Try address only mapping */
2031       m_key.port = 0;
2032       m_key.protocol = 0;
2033       kv.key = m_key.as_u64;
2034       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2035         return 1;
2036     }
2037
2038   m = pool_elt_at_index (sm->static_mappings, value.value);
2039
2040   if (by_external)
2041     {
2042       if (vec_len (m->locals))
2043         {
2044           hi = vec_len (m->locals) - 1;
2045           rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
2046           while (lo < hi)
2047             {
2048               mid = ((hi - lo) >> 1) + lo;
2049               (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
2050             }
2051           if (!(m->locals[lo].prefix >= rand))
2052             return 1;
2053           mapping->addr = m->locals[lo].addr;
2054           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
2055         }
2056       else
2057         {
2058           mapping->addr = m->local_addr;
2059           /* Address only mapping doesn't change port */
2060           mapping->port = m->addr_only ? match.port
2061             : clib_host_to_net_u16 (m->local_port);
2062         }
2063       mapping->fib_index = m->fib_index;
2064       mapping->protocol = m->proto;
2065     }
2066   else
2067     {
2068       mapping->addr = m->external_addr;
2069       /* Address only mapping doesn't change port */
2070       mapping->port = m->addr_only ? match.port
2071         : clib_host_to_net_u16 (m->external_port);
2072       mapping->fib_index = sm->outside_fib_index;
2073     }
2074
2075   if (PREDICT_FALSE(is_addr_only != 0))
2076     *is_addr_only = m->addr_only;
2077
2078   if (PREDICT_FALSE(twice_nat != 0))
2079     *twice_nat = m->twice_nat;
2080
2081   if (PREDICT_FALSE(lb != 0))
2082     *lb = vec_len (m->locals) > 0;
2083
2084   return 0;
2085 }
2086
2087 static_always_inline u16
2088 snat_random_port (u16 min, u16 max)
2089 {
2090   snat_main_t *sm = &snat_main;
2091   return min + random_u32 (&sm->random_seed) /
2092     (random_u32_max() / (max - min + 1) + 1);
2093 }
2094
2095 int
2096 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2097                                      u32 fib_index,
2098                                      u32 thread_index,
2099                                      snat_session_key_t * k,
2100                                      u32 * address_indexp,
2101                                      u16 port_per_thread,
2102                                      u32 snat_thread_index)
2103 {
2104   snat_main_t *sm = &snat_main;
2105
2106   return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
2107                                  address_indexp, port_per_thread,
2108                                  snat_thread_index);
2109 }
2110
2111 static int
2112 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2113                                  u32 fib_index,
2114                                  u32 thread_index,
2115                                  snat_session_key_t * k,
2116                                  u32 * address_indexp,
2117                                  u16 port_per_thread,
2118                                  u32 snat_thread_index)
2119 {
2120   int i, gi = 0;
2121   snat_address_t *a, *ga = 0;
2122   u32 portnum;
2123
2124   for (i = 0; i < vec_len (addresses); i++)
2125     {
2126       a = addresses + i;
2127       switch (k->protocol)
2128         {
2129 #define _(N, j, n, s) \
2130         case SNAT_PROTOCOL_##N: \
2131           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2132             { \
2133               if (a->fib_index == fib_index) \
2134                 { \
2135                   while (1) \
2136                     { \
2137                       portnum = (port_per_thread * \
2138                         snat_thread_index) + \
2139                         snat_random_port(1, port_per_thread) + 1024; \
2140                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2141                         continue; \
2142                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2143                       a->busy_##n##_ports_per_thread[thread_index]++; \
2144                       a->busy_##n##_ports++; \
2145                       k->addr = a->addr; \
2146                       k->port = clib_host_to_net_u16(portnum); \
2147                       *address_indexp = i; \
2148                       return 0; \
2149                     } \
2150                 } \
2151               else if (a->fib_index == ~0) \
2152                 { \
2153                   ga = a; \
2154                   gi = i; \
2155                 } \
2156             } \
2157           break;
2158           foreach_snat_protocol
2159 #undef _
2160         default:
2161           clib_warning("unknown protocol");
2162           return 1;
2163         }
2164
2165     }
2166
2167   if (ga)
2168     {
2169       a = ga;
2170       switch (k->protocol)
2171         {
2172 #define _(N, j, n, s) \
2173         case SNAT_PROTOCOL_##N: \
2174           while (1) \
2175             { \
2176               portnum = (port_per_thread * \
2177                 snat_thread_index) + \
2178                 snat_random_port(1, port_per_thread) + 1024; \
2179               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2180                 continue; \
2181               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2182               a->busy_##n##_ports_per_thread[thread_index]++; \
2183               a->busy_##n##_ports++; \
2184               k->addr = a->addr; \
2185               k->port = clib_host_to_net_u16(portnum); \
2186               *address_indexp = gi; \
2187               return 0; \
2188             }
2189           break;
2190           foreach_snat_protocol
2191 #undef _
2192         default:
2193           clib_warning ("unknown protocol");
2194           return 1;
2195         }
2196     }
2197
2198   /* Totally out of translations to use... */
2199   snat_ipfix_logging_addresses_exhausted(0);
2200   return 1;
2201 }
2202
2203 static int
2204 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2205                               u32 fib_index,
2206                               u32 thread_index,
2207                               snat_session_key_t * k,
2208                               u32 * address_indexp,
2209                               u16 port_per_thread,
2210                               u32 snat_thread_index)
2211 {
2212   snat_main_t *sm = &snat_main;
2213   snat_address_t *a = addresses;
2214   u16 m, ports, portnum, A, j;
2215   m = 16 - (sm->psid_offset + sm->psid_length);
2216   ports = (1 << (16 - sm->psid_length)) - (1 << m);
2217
2218   if (!vec_len (addresses))
2219     goto exhausted;
2220
2221   switch (k->protocol)
2222     {
2223 #define _(N, i, n, s) \
2224     case SNAT_PROTOCOL_##N: \
2225       if (a->busy_##n##_ports < ports) \
2226         { \
2227           while (1) \
2228             { \
2229               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2230               j = snat_random_port(0, pow2_mask(m)); \
2231               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2232               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2233                 continue; \
2234               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2235               a->busy_##n##_ports++; \
2236               k->addr = a->addr; \
2237               k->port = clib_host_to_net_u16 (portnum); \
2238               *address_indexp = i; \
2239               return 0; \
2240             } \
2241         } \
2242       break;
2243       foreach_snat_protocol
2244 #undef _
2245     default:
2246       clib_warning("unknown protocol");
2247       return 1;
2248     }
2249
2250 exhausted:
2251   /* Totally out of translations to use... */
2252   snat_ipfix_logging_addresses_exhausted(0);
2253   return 1;
2254 }
2255
2256 void
2257 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2258 {
2259   dpo_id_t dpo_v4 = DPO_INVALID;
2260   fib_prefix_t pfx = {
2261     .fp_proto = FIB_PROTOCOL_IP4,
2262     .fp_len = 32,
2263     .fp_addr.ip4.as_u32 = addr.as_u32,
2264   };
2265
2266   if (is_add)
2267     {
2268       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2269       fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
2270                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2271       dpo_reset (&dpo_v4);
2272     }
2273   else
2274     {
2275       fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2276     }
2277 }
2278
2279 uword
2280 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2281 {
2282   u32 *r = va_arg (*args, u32 *);
2283
2284   if (0);
2285 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2286   foreach_snat_protocol
2287 #undef _
2288   else
2289     return 0;
2290   return 1;
2291 }
2292
2293 u8 *
2294 format_snat_protocol (u8 * s, va_list * args)
2295 {
2296   u32 i = va_arg (*args, u32);
2297   u8 *t = 0;
2298
2299   switch (i)
2300     {
2301 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2302       foreach_snat_protocol
2303 #undef _
2304     default:
2305       s = format (s, "unknown");
2306       return s;
2307     }
2308   s = format (s, "%s", t);
2309   return s;
2310 }
2311
2312 static u32
2313 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2314 {
2315   snat_main_t *sm = &snat_main;
2316   u32 next_worker_index = 0;
2317   u32 hash;
2318
2319   next_worker_index = sm->first_worker_index;
2320   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2321          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2322
2323   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2324     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2325   else
2326     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2327
2328   return next_worker_index;
2329 }
2330
2331 static u32
2332 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2333 {
2334   snat_main_t *sm = &snat_main;
2335   udp_header_t *udp;
2336   u16 port;
2337   snat_session_key_t m_key;
2338   clib_bihash_kv_8_8_t kv, value;
2339   snat_static_mapping_t *m;
2340   nat_ed_ses_key_t key;
2341   clib_bihash_kv_16_8_t s_kv, s_value;
2342   snat_main_per_thread_data_t *tsm;
2343   snat_session_t *s;
2344   int i;
2345   u32 proto;
2346   u32 next_worker_index = 0;
2347
2348   /* first try static mappings without port */
2349   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2350     {
2351       m_key.addr = ip0->dst_address;
2352       m_key.port = 0;
2353       m_key.protocol = 0;
2354       m_key.fib_index = rx_fib_index0;
2355       kv.key = m_key.as_u64;
2356       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2357         {
2358           m = pool_elt_at_index (sm->static_mappings, value.value);
2359           return m->worker_index;
2360         }
2361     }
2362
2363   proto = ip_proto_to_snat_proto (ip0->protocol);
2364   udp = ip4_next_header (ip0);
2365   port = udp->dst_port;
2366
2367   if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2368     {
2369       if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2370         return vlib_get_thread_index ();
2371
2372       if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2373         {
2374           nat_reass_ip4_t *reass;
2375
2376           reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2377                                       ip0->fragment_id, ip0->protocol);
2378
2379           if (reass && (reass->thread_index != (u32) ~ 0))
2380             return reass->thread_index;
2381           else
2382             return vlib_get_thread_index ();
2383         }
2384     }
2385
2386   /* unknown protocol */
2387   if (PREDICT_FALSE (proto == ~0))
2388     {
2389       key.l_addr = ip0->dst_address;
2390       key.r_addr = ip0->src_address;
2391       key.fib_index = rx_fib_index0;
2392       key.proto = ip0->protocol;
2393       key.r_port = 0;
2394       key.l_port = 0;
2395       s_kv.key[0] = key.as_u64[0];
2396       s_kv.key[1] = key.as_u64[1];
2397
2398       if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2399         {
2400           for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2401             {
2402               tsm = vec_elt_at_index (sm->per_thread_data, i);
2403               if (!pool_is_free_index(tsm->sessions, s_value.value))
2404                 {
2405                   s = pool_elt_at_index (tsm->sessions, s_value.value);
2406                   if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2407                       s->out2in.port == ip0->protocol &&
2408                       snat_is_unk_proto_session (s))
2409                     return i;
2410                 }
2411             }
2412          }
2413
2414       /* if no session use current thread */
2415       return vlib_get_thread_index ();
2416     }
2417
2418   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2419     {
2420       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2421       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2422       if (!icmp_is_error_message (icmp))
2423         port = echo->identifier;
2424       else
2425         {
2426           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2427           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2428           void *l4_header = ip4_next_header (inner_ip);
2429           switch (proto)
2430             {
2431             case SNAT_PROTOCOL_ICMP:
2432               icmp = (icmp46_header_t*)l4_header;
2433               echo = (icmp_echo_header_t *)(icmp + 1);
2434               port = echo->identifier;
2435               break;
2436             case SNAT_PROTOCOL_UDP:
2437             case SNAT_PROTOCOL_TCP:
2438               port = ((tcp_udp_header_t*)l4_header)->src_port;
2439               break;
2440             default:
2441               return vlib_get_thread_index ();
2442             }
2443         }
2444     }
2445
2446   /* try static mappings with port */
2447   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2448     {
2449       m_key.addr = ip0->dst_address;
2450       m_key.port = clib_net_to_host_u16 (port);
2451       m_key.protocol = proto;
2452       m_key.fib_index = rx_fib_index0;
2453       kv.key = m_key.as_u64;
2454       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2455         {
2456           m = pool_elt_at_index (sm->static_mappings, value.value);
2457           return m->worker_index;
2458         }
2459     }
2460
2461   /* worker by outside port */
2462   next_worker_index = sm->first_worker_index;
2463   next_worker_index +=
2464     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2465   return next_worker_index;
2466 }
2467
2468 static clib_error_t *
2469 snat_config (vlib_main_t * vm, unformat_input_t * input)
2470 {
2471   snat_main_t * sm = &snat_main;
2472   nat66_main_t * nm = &nat66_main;
2473   u32 translation_buckets = 1024;
2474   u32 translation_memory_size = 128<<20;
2475   u32 user_buckets = 128;
2476   u32 user_memory_size = 64<<20;
2477   u32 max_translations_per_user = 100;
2478   u32 outside_vrf_id = 0;
2479   u32 outside_ip6_vrf_id = 0;
2480   u32 inside_vrf_id = 0;
2481   u32 static_mapping_buckets = 1024;
2482   u32 static_mapping_memory_size = 64<<20;
2483   u32 nat64_bib_buckets = 1024;
2484   u32 nat64_bib_memory_size = 128 << 20;
2485   u32 nat64_st_buckets = 2048;
2486   u32 nat64_st_memory_size = 256 << 20;
2487   u8 static_mapping_only = 0;
2488   u8 static_mapping_connection_tracking = 0;
2489   snat_main_per_thread_data_t *tsm;
2490   dslite_main_t * dm = &dslite_main;
2491
2492   sm->deterministic = 0;
2493   sm->out2in_dpo = 0;
2494
2495   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2496     {
2497       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2498         ;
2499       else if (unformat (input, "translation hash memory %d",
2500                          &translation_memory_size));
2501       else if (unformat (input, "user hash buckets %d", &user_buckets))
2502         ;
2503       else if (unformat (input, "user hash memory %d",
2504                          &user_memory_size))
2505         ;
2506       else if (unformat (input, "max translations per user %d",
2507                          &max_translations_per_user))
2508         ;
2509       else if (unformat (input, "outside VRF id %d",
2510                          &outside_vrf_id))
2511         ;
2512       else if (unformat (input, "outside ip6 VRF id %d",
2513                          &outside_ip6_vrf_id))
2514         ;
2515       else if (unformat (input, "inside VRF id %d",
2516                          &inside_vrf_id))
2517         ;
2518       else if (unformat (input, "static mapping only"))
2519         {
2520           static_mapping_only = 1;
2521           if (unformat (input, "connection tracking"))
2522             static_mapping_connection_tracking = 1;
2523         }
2524       else if (unformat (input, "deterministic"))
2525         sm->deterministic = 1;
2526       else if (unformat (input, "nat64 bib hash buckets %d",
2527                          &nat64_bib_buckets))
2528         ;
2529       else if (unformat (input, "nat64 bib hash memory %d",
2530                          &nat64_bib_memory_size))
2531         ;
2532       else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2533         ;
2534       else if (unformat (input, "nat64 st hash memory %d",
2535                          &nat64_st_memory_size))
2536         ;
2537       else if (unformat (input, "out2in dpo"))
2538         sm->out2in_dpo = 1;
2539       else if (unformat (input, "dslite ce"))
2540         dslite_set_ce(dm, 1);
2541       else
2542         return clib_error_return (0, "unknown input '%U'",
2543                                   format_unformat_error, input);
2544     }
2545
2546   /* for show commands, etc. */
2547   sm->translation_buckets = translation_buckets;
2548   sm->translation_memory_size = translation_memory_size;
2549   /* do not exceed load factor 10 */
2550   sm->max_translations = 10 * translation_buckets;
2551   sm->user_buckets = user_buckets;
2552   sm->user_memory_size = user_memory_size;
2553   sm->max_translations_per_user = max_translations_per_user;
2554   sm->outside_vrf_id = outside_vrf_id;
2555   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2556                                                              outside_vrf_id,
2557                                                              FIB_SOURCE_PLUGIN_HI);
2558   nm->outside_vrf_id = outside_ip6_vrf_id;
2559   nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2560                                                              outside_ip6_vrf_id,
2561                                                              FIB_SOURCE_PLUGIN_HI);
2562   sm->inside_vrf_id = inside_vrf_id;
2563   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2564                                                             inside_vrf_id,
2565                                                             FIB_SOURCE_PLUGIN_HI);
2566   sm->static_mapping_only = static_mapping_only;
2567   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2568
2569   nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2570                  nat64_st_memory_size);
2571
2572   if (sm->deterministic)
2573     {
2574       sm->in2out_node_index = snat_det_in2out_node.index;
2575       sm->in2out_output_node_index = ~0;
2576       sm->out2in_node_index = snat_det_out2in_node.index;
2577       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2578       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2579     }
2580   else
2581     {
2582       sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2583       sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2584       sm->in2out_node_index = snat_in2out_node.index;
2585       sm->in2out_output_node_index = snat_in2out_output_node.index;
2586       sm->out2in_node_index = snat_out2in_node.index;
2587       if (!static_mapping_only ||
2588           (static_mapping_only && static_mapping_connection_tracking))
2589         {
2590           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2591           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2592
2593           vec_foreach (tsm, sm->per_thread_data)
2594             {
2595               clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2596                                     translation_memory_size);
2597
2598               clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2599                                     translation_memory_size);
2600
2601               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2602                                     user_memory_size);
2603             }
2604
2605           clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2606                                  translation_buckets, translation_memory_size);
2607
2608           clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2609                                  translation_buckets, translation_memory_size);
2610         }
2611       else
2612         {
2613           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2614           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2615         }
2616       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2617                             "static_mapping_by_local", static_mapping_buckets,
2618                             static_mapping_memory_size);
2619
2620       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2621                             "static_mapping_by_external", static_mapping_buckets,
2622                             static_mapping_memory_size);
2623     }
2624
2625   return 0;
2626 }
2627
2628 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2629
2630 u8 * format_snat_session_state (u8 * s, va_list * args)
2631 {
2632   u32 i = va_arg (*args, u32);
2633   u8 *t = 0;
2634
2635   switch (i)
2636     {
2637 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2638     foreach_snat_session_state
2639 #undef _
2640     default:
2641       t = format (t, "unknown");
2642     }
2643   s = format (s, "%s", t);
2644   return s;
2645 }
2646
2647 u8 * format_snat_key (u8 * s, va_list * args)
2648 {
2649   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2650
2651   s = format (s, "%U proto %U port %d fib %d",
2652               format_ip4_address, &key->addr,
2653               format_snat_protocol, key->protocol,
2654               clib_net_to_host_u16 (key->port), key->fib_index);
2655   return s;
2656 }
2657
2658 u8 * format_snat_session (u8 * s, va_list * args)
2659 {
2660   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2661   snat_session_t * sess = va_arg (*args, snat_session_t *);
2662
2663   if (snat_is_unk_proto_session (sess))
2664     {
2665       s = format (s, "  i2o %U proto %u fib %u\n",
2666                   format_ip4_address, &sess->in2out.addr,
2667                   clib_net_to_host_u16 (sess->in2out.port),
2668                   sess->in2out.fib_index);
2669       s = format (s, "    o2i %U proto %u fib %u\n",
2670                   format_ip4_address, &sess->out2in.addr,
2671                   clib_net_to_host_u16 (sess->out2in.port),
2672                   sess->out2in.fib_index);
2673     }
2674   else
2675     {
2676       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
2677       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
2678     }
2679   if (is_twice_nat_session (sess))
2680     {
2681       s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
2682                   format_ip4_address, &sess->ext_host_addr,
2683                   clib_net_to_host_u16 (sess->ext_host_port),
2684                   format_ip4_address, &sess->ext_host_nat_addr,
2685                   clib_net_to_host_u16 (sess->ext_host_nat_port));
2686     }
2687   else
2688     {
2689       if (sess->ext_host_addr.as_u32)
2690           s = format (s, "       external host %U\n",
2691                       format_ip4_address, &sess->ext_host_addr);
2692     }
2693   s = format (s, "       last heard %.2f\n", sess->last_heard);
2694   s = format (s, "       total pkts %d, total bytes %lld\n",
2695               sess->total_pkts, sess->total_bytes);
2696   if (snat_is_session_static (sess))
2697     s = format (s, "       static translation\n");
2698   else
2699     s = format (s, "       dynamic translation\n");
2700   if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2701     s = format (s, "       load-balancing\n");
2702   if (is_twice_nat_session (sess))
2703     s = format (s, "       twice-nat\n");
2704
2705   return s;
2706 }
2707
2708 u8 * format_snat_user (u8 * s, va_list * args)
2709 {
2710   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2711   snat_user_t * u = va_arg (*args, snat_user_t *);
2712   int verbose = va_arg (*args, int);
2713   dlist_elt_t * head, * elt;
2714   u32 elt_index, head_index;
2715   u32 session_index;
2716   snat_session_t * sess;
2717
2718   s = format (s, "%U: %d dynamic translations, %d static translations\n",
2719               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2720
2721   if (verbose == 0)
2722     return s;
2723
2724   if (u->nsessions || u->nstaticsessions)
2725     {
2726       head_index = u->sessions_per_user_list_head_index;
2727       head = pool_elt_at_index (sm->list_pool, head_index);
2728
2729       elt_index = head->next;
2730       elt = pool_elt_at_index (sm->list_pool, elt_index);
2731       session_index = elt->value;
2732
2733       while (session_index != ~0)
2734         {
2735           sess = pool_elt_at_index (sm->sessions, session_index);
2736
2737           s = format (s, "  %U\n", format_snat_session, sm, sess);
2738
2739           elt_index = elt->next;
2740           elt = pool_elt_at_index (sm->list_pool, elt_index);
2741           session_index = elt->value;
2742         }
2743     }
2744
2745   return s;
2746 }
2747
2748 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2749 {
2750   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2751   nat44_lb_addr_port_t *local;
2752
2753   if (m->addr_only)
2754       s = format (s, "local %U external %U vrf %d %s",
2755                   format_ip4_address, &m->local_addr,
2756                   format_ip4_address, &m->external_addr,
2757                   m->vrf_id,
2758                   m->twice_nat == TWICE_NAT ? "twice-nat" :
2759                   m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "");
2760   else
2761    {
2762       if (vec_len (m->locals))
2763         {
2764           s = format (s, "%U vrf %d external %U:%d %s %s",
2765                       format_snat_protocol, m->proto,
2766                       m->vrf_id,
2767                       format_ip4_address, &m->external_addr, m->external_port,
2768                       m->twice_nat == TWICE_NAT ? "twice-nat" :
2769                       m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
2770                       m->out2in_only ? "out2in-only" : "");
2771           vec_foreach (local, m->locals)
2772             s = format (s, "\n  local %U:%d probability %d\%",
2773                         format_ip4_address, &local->addr, local->port,
2774                         local->probability);
2775         }
2776       else
2777         s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
2778                     format_snat_protocol, m->proto,
2779                     format_ip4_address, &m->local_addr, m->local_port,
2780                     format_ip4_address, &m->external_addr, m->external_port,
2781                     m->vrf_id,
2782                     m->twice_nat == TWICE_NAT ? "twice-nat" :
2783                     m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
2784                     m->out2in_only ? "out2in-only" : "");
2785    }
2786   return s;
2787 }
2788
2789 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2790 {
2791   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2792   vnet_main_t *vnm = vnet_get_main();
2793
2794   if (m->addr_only)
2795       s = format (s, "local %U external %U vrf %d",
2796                   format_ip4_address, &m->l_addr,
2797                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
2798                   m->vrf_id);
2799   else
2800       s = format (s, "%U local %U:%d external %U:%d vrf %d",
2801                   format_snat_protocol, m->proto,
2802                   format_ip4_address, &m->l_addr, m->l_port,
2803                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
2804                   m->e_port, m->vrf_id);
2805
2806   return s;
2807 }
2808
2809 u8 * format_det_map_ses (u8 * s, va_list * args)
2810 {
2811   snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2812   ip4_address_t in_addr, out_addr;
2813   u32 in_offset, out_offset;
2814   snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2815   u32 * i = va_arg (*args, u32 *);
2816
2817   u32 user_index = *i / SNAT_DET_SES_PER_USER;
2818   in_addr.as_u32 = clib_host_to_net_u32 (
2819     clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2820   in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2821     clib_net_to_host_u32(det_map->in_addr.as_u32);
2822   out_offset = in_offset / det_map->sharing_ratio;
2823   out_addr.as_u32 = clib_host_to_net_u32(
2824     clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2825   s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2826               format_ip4_address, &in_addr,
2827               clib_net_to_host_u16 (ses->in_port),
2828               format_ip4_address, &out_addr,
2829               clib_net_to_host_u16 (ses->out.out_port),
2830               format_ip4_address, &ses->out.ext_host_addr,
2831               clib_net_to_host_u16 (ses->out.ext_host_port),
2832               format_snat_session_state, ses->state,
2833               ses->expire);
2834
2835   return s;
2836 }
2837
2838 static void
2839 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2840                                  uword opaque,
2841                                  u32 sw_if_index,
2842                                  ip4_address_t * address,
2843                                  u32 address_length,
2844                                  u32 if_address_index,
2845                                  u32 is_delete)
2846 {
2847   snat_main_t *sm = &snat_main;
2848   snat_static_map_resolve_t *rp;
2849   snat_static_mapping_t *m;
2850   snat_session_key_t m_key;
2851   clib_bihash_kv_8_8_t kv, value;
2852   int i, rv;
2853   ip4_address_t l_addr;
2854
2855   for (i = 0; i < vec_len (sm->to_resolve); i++)
2856     {
2857       rp = sm->to_resolve + i;
2858       if (rp->addr_only == 0)
2859         continue;
2860       if (rp->sw_if_index == sw_if_index)
2861         goto match;
2862     }
2863
2864   return;
2865
2866 match:
2867   m_key.addr.as_u32 = address->as_u32;
2868   m_key.port = rp->addr_only ? 0 : rp->e_port;
2869   m_key.protocol = rp->addr_only ? 0 : rp->proto;
2870   m_key.fib_index = sm->outside_fib_index;
2871   kv.key = m_key.as_u64;
2872   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2873     m = 0;
2874   else
2875     m = pool_elt_at_index (sm->static_mappings, value.value);
2876
2877   if (!is_delete)
2878     {
2879       /* Don't trip over lease renewal, static config */
2880       if (m)
2881         return;
2882     }
2883   else
2884     {
2885       if (!m)
2886         return;
2887     }
2888
2889   /* Indetity mapping? */
2890   if (rp->l_addr.as_u32 == 0)
2891     l_addr.as_u32 = address[0].as_u32;
2892   else
2893     l_addr.as_u32 = rp->l_addr.as_u32;
2894   /* Add the static mapping */
2895   rv = snat_add_static_mapping (l_addr,
2896                                 address[0],
2897                                 rp->l_port,
2898                                 rp->e_port,
2899                                 rp->vrf_id,
2900                                 rp->addr_only,
2901                                 ~0 /* sw_if_index */,
2902                                 rp->proto,
2903                                 !is_delete,
2904                                 0, 0, rp->tag);
2905   if (rv)
2906     clib_warning ("snat_add_static_mapping returned %d", rv);
2907 }
2908
2909 static void
2910 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2911                                        uword opaque,
2912                                        u32 sw_if_index,
2913                                        ip4_address_t * address,
2914                                        u32 address_length,
2915                                        u32 if_address_index,
2916                                        u32 is_delete)
2917 {
2918   snat_main_t *sm = &snat_main;
2919   snat_static_map_resolve_t *rp;
2920   ip4_address_t l_addr;
2921   int i, j;
2922   int rv;
2923   u8 twice_nat = 0;
2924   snat_address_t *addresses = sm->addresses;
2925
2926   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2927     {
2928       if (sw_if_index == sm->auto_add_sw_if_indices[i])
2929           goto match;
2930     }
2931
2932   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
2933     {
2934       twice_nat = 1;
2935       addresses = sm->twice_nat_addresses;
2936       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
2937           goto match;
2938     }
2939
2940   return;
2941
2942 match:
2943   if (!is_delete)
2944     {
2945       /* Don't trip over lease renewal, static config */
2946       for (j = 0; j < vec_len(addresses); j++)
2947         if (addresses[j].addr.as_u32 == address->as_u32)
2948           return;
2949
2950       snat_add_address (sm, address, ~0, twice_nat);
2951       /* Scan static map resolution vector */
2952       for (j = 0; j < vec_len (sm->to_resolve); j++)
2953         {
2954           rp = sm->to_resolve + j;
2955           if (rp->addr_only)
2956             continue;
2957           /* On this interface? */
2958           if (rp->sw_if_index == sw_if_index)
2959             {
2960               /* Indetity mapping? */
2961               if (rp->l_addr.as_u32 == 0)
2962                 l_addr.as_u32 = address[0].as_u32;
2963               else
2964                 l_addr.as_u32 = rp->l_addr.as_u32;
2965               /* Add the static mapping */
2966               rv = snat_add_static_mapping (l_addr,
2967                                             address[0],
2968                                             rp->l_port,
2969                                             rp->e_port,
2970                                             rp->vrf_id,
2971                                             rp->addr_only,
2972                                             ~0 /* sw_if_index */,
2973                                             rp->proto,
2974                                             rp->is_add,
2975                                             0, 0, rp->tag);
2976               if (rv)
2977                 clib_warning ("snat_add_static_mapping returned %d",
2978                               rv);
2979             }
2980         }
2981       return;
2982     }
2983   else
2984     {
2985       (void) snat_del_address(sm, address[0], 1, twice_nat);
2986       return;
2987     }
2988 }
2989
2990
2991 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
2992                                 u8 twice_nat)
2993 {
2994   ip4_main_t * ip4_main = sm->ip4_main;
2995   ip4_address_t * first_int_addr;
2996   snat_static_map_resolve_t *rp;
2997   u32 *indices_to_delete = 0;
2998   int i, j;
2999   u32 *auto_add_sw_if_indices =
3000     twice_nat ? sm->auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3001
3002   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3003                                                 0 /* just want the address*/);
3004
3005   for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
3006     {
3007       if (auto_add_sw_if_indices[i] == sw_if_index)
3008         {
3009           if (is_del)
3010             {
3011               /* if have address remove it */
3012               if (first_int_addr)
3013                   (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3014               else
3015                 {
3016                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3017                     {
3018                       rp = sm->to_resolve + j;
3019                       if (rp->sw_if_index == sw_if_index)
3020                         vec_add1 (indices_to_delete, j);
3021                     }
3022                   if (vec_len(indices_to_delete))
3023                     {
3024                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3025                         vec_del1(sm->to_resolve, j);
3026                       vec_free(indices_to_delete);
3027                     }
3028                 }
3029               if (twice_nat)
3030                 vec_del1(sm->auto_add_sw_if_indices_twice_nat, i);
3031               else
3032                 vec_del1(sm->auto_add_sw_if_indices, i);
3033             }
3034           else
3035             return VNET_API_ERROR_VALUE_EXIST;
3036
3037           return 0;
3038         }
3039     }
3040
3041   if (is_del)
3042     return VNET_API_ERROR_NO_SUCH_ENTRY;
3043
3044   /* add to the auto-address list */
3045   if (twice_nat)
3046     vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3047   else
3048     vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3049
3050   /* If the address is already bound - or static - add it now */
3051   if (first_int_addr)
3052       snat_add_address (sm, first_int_addr, ~0, twice_nat);
3053
3054   return 0;
3055 }
3056
3057 int
3058 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3059                    snat_protocol_t proto, u32 vrf_id, int is_in)
3060 {
3061   snat_main_per_thread_data_t *tsm;
3062   clib_bihash_kv_8_8_t kv, value;
3063   ip4_header_t ip;
3064   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3065   snat_session_key_t key;
3066   snat_session_t *s;
3067   clib_bihash_8_8_t *t;
3068   snat_user_key_t u_key;
3069   snat_user_t *u;
3070
3071   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3072   if (sm->num_workers > 1)
3073     tsm =
3074       vec_elt_at_index (sm->per_thread_data,
3075                         sm->worker_in2out_cb (&ip, fib_index));
3076   else
3077     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3078
3079   key.addr.as_u32 = addr->as_u32;
3080   key.port = clib_host_to_net_u16 (port);
3081   key.protocol = proto;
3082   key.fib_index = fib_index;
3083   kv.key = key.as_u64;
3084   t = is_in ? &tsm->in2out : &tsm->out2in;
3085   if (!clib_bihash_search_8_8 (t, &kv, &value))
3086     {
3087       s = pool_elt_at_index (tsm->sessions, value.value);
3088       kv.key = s->in2out.as_u64;
3089       clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3090       kv.key = s->out2in.as_u64;
3091       clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3092       u_key.addr = s->in2out.addr;
3093       u_key.fib_index = s->in2out.fib_index;
3094       kv.key = u_key.as_u64;
3095       if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3096         {
3097           u = pool_elt_at_index (tsm->users, value.value);
3098           u->nsessions--;
3099         }
3100       clib_dlist_remove (tsm->list_pool, s->per_user_index);
3101       pool_put (tsm->sessions, s);
3102       return 0;
3103     }
3104
3105   return VNET_API_ERROR_NO_SUCH_ENTRY;
3106 }
3107
3108 void
3109 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
3110 {
3111   snat_main_t *sm = &snat_main;
3112
3113   sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3114   sm->psid = psid;
3115   sm->psid_offset = psid_offset;
3116   sm->psid_length = psid_length;
3117 }
3118
3119 void
3120 nat_set_alloc_addr_and_port_default (void)
3121 {
3122   snat_main_t *sm = &snat_main;
3123
3124   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3125 }
3126