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