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