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