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