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