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