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