NAT44: endpoint dependent mode (VPP-1273)
[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 = sm->outside_fib_index;
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 = sm->outside_fib_index;
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 = sm->outside_fib_index;
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 = sm->outside_fib_index;
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 = sm->outside_fib_index;
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 = sm->outside_fib_index;
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
1590   if (sm->out2in_dpo && !is_inside)
1591     return VNET_API_ERROR_UNSUPPORTED;
1592
1593   pool_foreach (i, sm->output_feature_interfaces,
1594   ({
1595     if (i->sw_if_index == sw_if_index)
1596       return VNET_API_ERROR_VALUE_EXIST;
1597   }));
1598
1599   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1600     feature_name = is_inside ?  "nat44-in2out-fast" : "nat44-out2in-fast";
1601   else
1602     {
1603       if (sm->num_workers > 1 && !sm->deterministic)
1604         feature_name = is_inside ?  "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1605       else if (sm->deterministic)
1606         feature_name = is_inside ?  "nat44-det-in2out" : "nat44-det-out2in";
1607       else if (sm->endpoint_dependent)
1608         feature_name = is_inside ?  "nat44-ed-in2out" : "nat44-ed-out2in";
1609       else
1610         feature_name = is_inside ?  "nat44-in2out" : "nat44-out2in";
1611     }
1612
1613   if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1614     sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index,
1615                                                       NAT_FQ_NELTS);
1616
1617   if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1618     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
1619                                                       NAT_FQ_NELTS);
1620
1621   pool_foreach (i, sm->interfaces,
1622   ({
1623     if (i->sw_if_index == sw_if_index)
1624       {
1625         if (is_del)
1626           {
1627             if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1628               {
1629                 if (is_inside)
1630                   i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1631                 else
1632                   i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1633
1634                 if (sm->num_workers > 1 && !sm->deterministic)
1635                   {
1636                     del_feature_name = "nat44-handoff-classify";
1637                     feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1638                                                  "nat44-out2in-worker-handoff";
1639                   }
1640                 else if (sm->deterministic)
1641                   {
1642                     del_feature_name = "nat44-det-classify";
1643                     feature_name = !is_inside ?  "nat44-det-in2out" :
1644                                                  "nat44-det-out2in";
1645                   }
1646                 else if (sm->endpoint_dependent)
1647                   {
1648                     del_feature_name = "nat44-ed-classify";
1649                     feature_name = !is_inside ?  "nat44-ed-in2out" :
1650                                                  "nat44-ed-out2in";
1651                   }
1652                 else
1653                   {
1654                     del_feature_name = "nat44-classify";
1655                     feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1656                   }
1657
1658                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1659                                              sw_if_index, 0, 0, 0);
1660                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1661                                              sw_if_index, 1, 0, 0);
1662                 if (!is_inside)
1663                   {
1664                     if (sm->endpoint_dependent)
1665                       vnet_feature_enable_disable ("ip4-local",
1666                                                    "nat44-ed-hairpinning",
1667                                                    sw_if_index, 1, 0, 0);
1668                     else
1669                       vnet_feature_enable_disable ("ip4-local",
1670                                                    "nat44-hairpinning",
1671                                                    sw_if_index, 1, 0, 0);
1672                   }
1673               }
1674             else
1675               {
1676                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1677                                              sw_if_index, 0, 0, 0);
1678                 pool_put (sm->interfaces, i);
1679                 if (is_inside)
1680                   {
1681                     if (sm->endpoint_dependent)
1682                       vnet_feature_enable_disable ("ip4-local",
1683                                                    "nat44-ed-hairpinning",
1684                                                    sw_if_index, 0, 0, 0);
1685                     else
1686                       vnet_feature_enable_disable ("ip4-local",
1687                                                    "nat44-hairpinning",
1688                                                    sw_if_index, 0, 0, 0);
1689                   }
1690               }
1691           }
1692         else
1693           {
1694             if ((nat_interface_is_inside(i) && is_inside) ||
1695                 (nat_interface_is_outside(i) && !is_inside))
1696               return 0;
1697
1698             if (sm->num_workers > 1 && !sm->deterministic)
1699               {
1700                 del_feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1701                                                  "nat44-out2in-worker-handoff";
1702                 feature_name = "nat44-handoff-classify";
1703               }
1704             else if (sm->deterministic)
1705               {
1706                 del_feature_name = !is_inside ?  "nat44-det-in2out" :
1707                                                  "nat44-det-out2in";
1708                 feature_name = "nat44-det-classify";
1709               }
1710             else if (sm->endpoint_dependent)
1711               {
1712                 del_feature_name = !is_inside ?  "nat44-ed-in2out" :
1713                                                  "nat44-ed-out2in";
1714                 feature_name = "nat44-ed-classify";
1715               }
1716             else
1717               {
1718                 del_feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1719                 feature_name = "nat44-classify";
1720               }
1721
1722             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1723                                          sw_if_index, 0, 0, 0);
1724             vnet_feature_enable_disable ("ip4-unicast", feature_name,
1725                                          sw_if_index, 1, 0, 0);
1726             if (!is_inside)
1727               {
1728                 if (sm->endpoint_dependent)
1729                   vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1730                                                sw_if_index, 0, 0, 0);
1731                 else
1732                   vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1733                                                sw_if_index, 0, 0, 0);
1734               }
1735             goto set_flags;
1736           }
1737
1738         goto fib;
1739       }
1740   }));
1741
1742   if (is_del)
1743     return VNET_API_ERROR_NO_SUCH_ENTRY;
1744
1745   pool_get (sm->interfaces, i);
1746   i->sw_if_index = sw_if_index;
1747   i->flags = 0;
1748   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1749
1750   if (is_inside && !sm->out2in_dpo)
1751     {
1752       if (sm->endpoint_dependent)
1753         vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1754                                      sw_if_index, 1, 0, 0);
1755       else
1756         vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1757                                      sw_if_index, 1, 0, 0);
1758     }
1759
1760 set_flags:
1761   if (is_inside)
1762     {
1763       i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1764       return 0;
1765     }
1766   else
1767     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1768
1769   /* Add/delete external addresses to FIB */
1770 fib:
1771   vec_foreach (ap, sm->addresses)
1772     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1773
1774   pool_foreach (m, sm->static_mappings,
1775   ({
1776     if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1777       continue;
1778
1779     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1780   }));
1781
1782   pool_foreach (dm, sm->det_maps,
1783   ({
1784     snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1785   }));
1786
1787   return 0;
1788 }
1789
1790 int snat_interface_add_del_output_feature (u32 sw_if_index,
1791                                            u8 is_inside,
1792                                            int is_del)
1793 {
1794   snat_main_t *sm = &snat_main;
1795   snat_interface_t *i;
1796   snat_address_t * ap;
1797   snat_static_mapping_t * m;
1798
1799   if (sm->deterministic ||
1800       (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1801     return VNET_API_ERROR_UNSUPPORTED;
1802
1803   pool_foreach (i, sm->interfaces,
1804   ({
1805     if (i->sw_if_index == sw_if_index)
1806       return VNET_API_ERROR_VALUE_EXIST;
1807   }));
1808
1809   if (is_inside)
1810     {
1811       if (sm->endpoint_dependent)
1812         {
1813           vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
1814                                        sw_if_index, !is_del, 0, 0);
1815           vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
1816                                        sw_if_index, !is_del, 0, 0);
1817         }
1818       else
1819         {
1820           vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1821                                        sw_if_index, !is_del, 0, 0);
1822           vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1823                                        sw_if_index, !is_del, 0, 0);
1824         }
1825       goto fq;
1826     }
1827
1828   if (sm->num_workers > 1)
1829     {
1830       vnet_feature_enable_disable ("ip4-unicast",
1831                                    "nat44-out2in-worker-handoff",
1832                                    sw_if_index, !is_del, 0, 0);
1833       vnet_feature_enable_disable ("ip4-output",
1834                                    "nat44-in2out-output-worker-handoff",
1835                                    sw_if_index, !is_del, 0, 0);
1836     }
1837   else
1838     {
1839       if (sm->endpoint_dependent)
1840         {
1841           vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-out2in",
1842                                        sw_if_index, !is_del, 0, 0);
1843           vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
1844                                        sw_if_index, !is_del, 0, 0);
1845         }
1846       else
1847         {
1848           vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
1849                                        sw_if_index, !is_del, 0, 0);
1850           vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1851                                        sw_if_index, !is_del, 0, 0);
1852         }
1853     }
1854
1855 fq:
1856   if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1857     sm->fq_in2out_output_index =
1858       vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1859
1860   if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1861     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1862
1863   pool_foreach (i, sm->output_feature_interfaces,
1864   ({
1865     if (i->sw_if_index == sw_if_index)
1866       {
1867         if (is_del)
1868           pool_put (sm->output_feature_interfaces, i);
1869         else
1870           return VNET_API_ERROR_VALUE_EXIST;
1871
1872         goto fib;
1873       }
1874   }));
1875
1876   if (is_del)
1877     return VNET_API_ERROR_NO_SUCH_ENTRY;
1878
1879   pool_get (sm->output_feature_interfaces, i);
1880   i->sw_if_index = sw_if_index;
1881   i->flags = 0;
1882   if (is_inside)
1883     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1884   else
1885     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1886
1887   /* Add/delete external addresses to FIB */
1888 fib:
1889   if (is_inside)
1890     return 0;
1891
1892   vec_foreach (ap, sm->addresses)
1893     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1894
1895   pool_foreach (m, sm->static_mappings,
1896   ({
1897     if (!(m->addr_only)  || (m->local_addr.as_u32 == m->external_addr.as_u32))
1898       continue;
1899
1900     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1901   }));
1902
1903   return 0;
1904 }
1905
1906 int snat_set_workers (uword * bitmap)
1907 {
1908   snat_main_t *sm = &snat_main;
1909   int i, j = 0;
1910
1911   if (sm->num_workers < 2)
1912     return VNET_API_ERROR_FEATURE_DISABLED;
1913
1914   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1915     return VNET_API_ERROR_INVALID_WORKER;
1916
1917   vec_free (sm->workers);
1918   clib_bitmap_foreach (i, bitmap,
1919     ({
1920       vec_add1(sm->workers, i);
1921       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
1922       j++;
1923     }));
1924
1925   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1926   sm->num_snat_thread = _vec_len (sm->workers);
1927
1928   return 0;
1929 }
1930
1931
1932 static void
1933 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1934                                        uword opaque,
1935                                        u32 sw_if_index,
1936                                        ip4_address_t * address,
1937                                        u32 address_length,
1938                                        u32 if_address_index,
1939                                        u32 is_delete);
1940
1941 static void
1942 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
1943                                  uword opaque,
1944                                  u32 sw_if_index,
1945                                  ip4_address_t * address,
1946                                  u32 address_length,
1947                                  u32 if_address_index,
1948                                  u32 is_delete);
1949
1950 static int
1951 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1952                                  u32 fib_index,
1953                                  u32 thread_index,
1954                                  snat_session_key_t * k,
1955                                  u32 * address_indexp,
1956                                  u16 port_per_thread,
1957                                  u32 snat_thread_index);
1958
1959 static clib_error_t * snat_init (vlib_main_t * vm)
1960 {
1961   snat_main_t * sm = &snat_main;
1962   clib_error_t * error = 0;
1963   ip4_main_t * im = &ip4_main;
1964   ip_lookup_main_t * lm = &im->lookup_main;
1965   uword *p;
1966   vlib_thread_registration_t *tr;
1967   vlib_thread_main_t *tm = vlib_get_thread_main ();
1968   uword *bitmap = 0;
1969   u32 i;
1970   ip4_add_del_interface_address_callback_t cb4;
1971   vlib_node_t * error_drop_node;
1972
1973   sm->vlib_main = vm;
1974   sm->vnet_main = vnet_get_main();
1975   sm->ip4_main = im;
1976   sm->ip4_lookup_main = lm;
1977   sm->api_main = &api_main;
1978   sm->first_worker_index = 0;
1979   sm->num_workers = 0;
1980   sm->num_snat_thread = 1;
1981   sm->workers = 0;
1982   sm->port_per_thread = 0xffff - 1024;
1983   sm->fq_in2out_index = ~0;
1984   sm->fq_out2in_index = ~0;
1985   sm->udp_timeout = SNAT_UDP_TIMEOUT;
1986   sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1987   sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1988   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1989   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
1990   sm->forwarding_enabled = 0;
1991   sm->log_class = vlib_log_register_class ("nat", 0);
1992   error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
1993   sm->error_node_index = error_drop_node->index;
1994
1995   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1996   if (p)
1997     {
1998       tr = (vlib_thread_registration_t *) p[0];
1999       if (tr)
2000         {
2001           sm->num_workers = tr->count;
2002           sm->first_worker_index = tr->first_index;
2003         }
2004     }
2005
2006   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2007
2008   /* Use all available workers by default */
2009   if (sm->num_workers > 1)
2010     {
2011       for (i=0; i < sm->num_workers; i++)
2012         bitmap = clib_bitmap_set (bitmap, i, 1);
2013       snat_set_workers(bitmap);
2014       clib_bitmap_free (bitmap);
2015     }
2016   else
2017     {
2018       sm->per_thread_data[0].snat_thread_index = 0;
2019     }
2020
2021   error = snat_api_init(vm, sm);
2022   if (error)
2023     return error;
2024
2025   /* Set up the interface address add/del callback */
2026   cb4.function = snat_ip4_add_del_interface_address_cb;
2027   cb4.function_opaque = 0;
2028
2029   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2030
2031   cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2032   cb4.function_opaque = 0;
2033
2034   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2035
2036   nat_dpo_module_init ();
2037
2038   /* Init IPFIX logging */
2039   snat_ipfix_logging_init(vm);
2040
2041   /* Init NAT64 */
2042   error = nat64_init(vm);
2043   if (error)
2044     return error;
2045
2046   dslite_init(vm);
2047
2048   nat66_init();
2049
2050   /* Init virtual fragmenentation reassembly */
2051   return nat_reass_init(vm);
2052 }
2053
2054 VLIB_INIT_FUNCTION (snat_init);
2055
2056 void snat_free_outside_address_and_port (snat_address_t * addresses,
2057                                          u32 thread_index,
2058                                          snat_session_key_t * k,
2059                                          u32 address_index)
2060 {
2061   snat_address_t *a;
2062   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2063
2064   ASSERT (address_index < vec_len (addresses));
2065
2066   a = addresses + address_index;
2067
2068   switch (k->protocol)
2069     {
2070 #define _(N, i, n, s) \
2071     case SNAT_PROTOCOL_##N: \
2072       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2073         port_host_byte_order) == 1); \
2074       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2075         port_host_byte_order, 0); \
2076       a->busy_##n##_ports--; \
2077       a->busy_##n##_ports_per_thread[thread_index]--; \
2078       break;
2079       foreach_snat_protocol
2080 #undef _
2081     default:
2082       nat_log_info ("unknown protocol");
2083       return;
2084     }
2085 }
2086
2087 /**
2088  * @brief Match NAT44 static mapping.
2089  *
2090  * @param sm          NAT main.
2091  * @param match       Address and port to match.
2092  * @param mapping     External or local address and port of the matched mapping.
2093  * @param by_external If 0 match by local address otherwise match by external
2094  *                    address.
2095  * @param is_addr_only If matched mapping is address only
2096  * @param twice_nat If matched mapping is twice NAT.
2097  * @param lb If matched mapping is load-balanced.
2098  *
2099  * @returns 0 if match found otherwise 1.
2100  */
2101 int snat_static_mapping_match (snat_main_t * sm,
2102                                snat_session_key_t match,
2103                                snat_session_key_t * mapping,
2104                                u8 by_external,
2105                                u8 *is_addr_only,
2106                                twice_nat_type_t *twice_nat,
2107                                u8 *lb)
2108 {
2109   clib_bihash_kv_8_8_t kv, value;
2110   snat_static_mapping_t *m;
2111   snat_session_key_t m_key;
2112   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2113   u32 rand, lo = 0, hi, mid;
2114
2115   if (by_external)
2116     mapping_hash = &sm->static_mapping_by_external;
2117
2118   m_key.addr = match.addr;
2119   m_key.port = clib_net_to_host_u16 (match.port);
2120   m_key.protocol = match.protocol;
2121   m_key.fib_index = match.fib_index;
2122
2123   kv.key = m_key.as_u64;
2124
2125   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2126     {
2127       /* Try address only mapping */
2128       m_key.port = 0;
2129       m_key.protocol = 0;
2130       kv.key = m_key.as_u64;
2131       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2132         return 1;
2133     }
2134
2135   m = pool_elt_at_index (sm->static_mappings, value.value);
2136
2137   if (by_external)
2138     {
2139       if (vec_len (m->locals))
2140         {
2141 get_local:
2142           hi = vec_len (m->locals) - 1;
2143           rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
2144           while (lo < hi)
2145             {
2146               mid = ((hi - lo) >> 1) + lo;
2147               (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
2148             }
2149           if (!(m->locals[lo].prefix >= rand))
2150             return 1;
2151           if (PREDICT_FALSE (sm->num_workers > 1))
2152             {
2153               ip4_header_t ip = {
2154                 .src_address = m->locals[lo].addr,
2155               };
2156               if (sm->worker_in2out_cb (&ip, m->fib_index) != vlib_get_thread_index ())
2157                 goto get_local;
2158             }
2159           mapping->addr = m->locals[lo].addr;
2160           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
2161         }
2162       else
2163         {
2164           mapping->addr = m->local_addr;
2165           /* Address only mapping doesn't change port */
2166           mapping->port = m->addr_only ? match.port
2167             : clib_host_to_net_u16 (m->local_port);
2168         }
2169       mapping->fib_index = m->fib_index;
2170       mapping->protocol = m->proto;
2171     }
2172   else
2173     {
2174       mapping->addr = m->external_addr;
2175       /* Address only mapping doesn't change port */
2176       mapping->port = m->addr_only ? match.port
2177         : clib_host_to_net_u16 (m->external_port);
2178       mapping->fib_index = sm->outside_fib_index;
2179     }
2180
2181   if (PREDICT_FALSE(is_addr_only != 0))
2182     *is_addr_only = m->addr_only;
2183
2184   if (PREDICT_FALSE(twice_nat != 0))
2185     *twice_nat = m->twice_nat;
2186
2187   if (PREDICT_FALSE(lb != 0))
2188     *lb = vec_len (m->locals) > 0;
2189
2190   return 0;
2191 }
2192
2193 static_always_inline u16
2194 snat_random_port (u16 min, u16 max)
2195 {
2196   snat_main_t *sm = &snat_main;
2197   return min + random_u32 (&sm->random_seed) /
2198     (random_u32_max() / (max - min + 1) + 1);
2199 }
2200
2201 int
2202 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2203                                      u32 fib_index,
2204                                      u32 thread_index,
2205                                      snat_session_key_t * k,
2206                                      u32 * address_indexp,
2207                                      u16 port_per_thread,
2208                                      u32 snat_thread_index)
2209 {
2210   snat_main_t *sm = &snat_main;
2211
2212   return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
2213                                  address_indexp, port_per_thread,
2214                                  snat_thread_index);
2215 }
2216
2217 static int
2218 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2219                                  u32 fib_index,
2220                                  u32 thread_index,
2221                                  snat_session_key_t * k,
2222                                  u32 * address_indexp,
2223                                  u16 port_per_thread,
2224                                  u32 snat_thread_index)
2225 {
2226   int i, gi = 0;
2227   snat_address_t *a, *ga = 0;
2228   u32 portnum;
2229
2230   for (i = 0; i < vec_len (addresses); i++)
2231     {
2232       a = addresses + i;
2233       switch (k->protocol)
2234         {
2235 #define _(N, j, n, s) \
2236         case SNAT_PROTOCOL_##N: \
2237           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2238             { \
2239               if (a->fib_index == fib_index) \
2240                 { \
2241                   while (1) \
2242                     { \
2243                       portnum = (port_per_thread * \
2244                         snat_thread_index) + \
2245                         snat_random_port(1, port_per_thread) + 1024; \
2246                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2247                         continue; \
2248                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2249                       a->busy_##n##_ports_per_thread[thread_index]++; \
2250                       a->busy_##n##_ports++; \
2251                       k->addr = a->addr; \
2252                       k->port = clib_host_to_net_u16(portnum); \
2253                       *address_indexp = i; \
2254                       return 0; \
2255                     } \
2256                 } \
2257               else if (a->fib_index == ~0) \
2258                 { \
2259                   ga = a; \
2260                   gi = i; \
2261                 } \
2262             } \
2263           break;
2264           foreach_snat_protocol
2265 #undef _
2266         default:
2267           nat_log_info ("unknown protocol");
2268           return 1;
2269         }
2270
2271     }
2272
2273   if (ga)
2274     {
2275       a = ga;
2276       switch (k->protocol)
2277         {
2278 #define _(N, j, n, s) \
2279         case SNAT_PROTOCOL_##N: \
2280           while (1) \
2281             { \
2282               portnum = (port_per_thread * \
2283                 snat_thread_index) + \
2284                 snat_random_port(1, port_per_thread) + 1024; \
2285               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2286                 continue; \
2287               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2288               a->busy_##n##_ports_per_thread[thread_index]++; \
2289               a->busy_##n##_ports++; \
2290               k->addr = a->addr; \
2291               k->port = clib_host_to_net_u16(portnum); \
2292               *address_indexp = gi; \
2293               return 0; \
2294             }
2295           break;
2296           foreach_snat_protocol
2297 #undef _
2298         default:
2299           nat_log_info ("unknown protocol");
2300           return 1;
2301         }
2302     }
2303
2304   /* Totally out of translations to use... */
2305   snat_ipfix_logging_addresses_exhausted(0);
2306   return 1;
2307 }
2308
2309 static int
2310 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2311                               u32 fib_index,
2312                               u32 thread_index,
2313                               snat_session_key_t * k,
2314                               u32 * address_indexp,
2315                               u16 port_per_thread,
2316                               u32 snat_thread_index)
2317 {
2318   snat_main_t *sm = &snat_main;
2319   snat_address_t *a = addresses;
2320   u16 m, ports, portnum, A, j;
2321   m = 16 - (sm->psid_offset + sm->psid_length);
2322   ports = (1 << (16 - sm->psid_length)) - (1 << m);
2323
2324   if (!vec_len (addresses))
2325     goto exhausted;
2326
2327   switch (k->protocol)
2328     {
2329 #define _(N, i, n, s) \
2330     case SNAT_PROTOCOL_##N: \
2331       if (a->busy_##n##_ports < ports) \
2332         { \
2333           while (1) \
2334             { \
2335               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2336               j = snat_random_port(0, pow2_mask(m)); \
2337               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2338               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2339                 continue; \
2340               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2341               a->busy_##n##_ports++; \
2342               k->addr = a->addr; \
2343               k->port = clib_host_to_net_u16 (portnum); \
2344               *address_indexp = i; \
2345               return 0; \
2346             } \
2347         } \
2348       break;
2349       foreach_snat_protocol
2350 #undef _
2351     default:
2352       nat_log_info ("unknown protocol");
2353       return 1;
2354     }
2355
2356 exhausted:
2357   /* Totally out of translations to use... */
2358   snat_ipfix_logging_addresses_exhausted(0);
2359   return 1;
2360 }
2361
2362 void
2363 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2364 {
2365   dpo_id_t dpo_v4 = DPO_INVALID;
2366   fib_prefix_t pfx = {
2367     .fp_proto = FIB_PROTOCOL_IP4,
2368     .fp_len = 32,
2369     .fp_addr.ip4.as_u32 = addr.as_u32,
2370   };
2371
2372   if (is_add)
2373     {
2374       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2375       fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
2376                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2377       dpo_reset (&dpo_v4);
2378     }
2379   else
2380     {
2381       fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2382     }
2383 }
2384
2385 uword
2386 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2387 {
2388   u32 *r = va_arg (*args, u32 *);
2389
2390   if (0);
2391 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2392   foreach_snat_protocol
2393 #undef _
2394   else
2395     return 0;
2396   return 1;
2397 }
2398
2399 u8 *
2400 format_snat_protocol (u8 * s, va_list * args)
2401 {
2402   u32 i = va_arg (*args, u32);
2403   u8 *t = 0;
2404
2405   switch (i)
2406     {
2407 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2408       foreach_snat_protocol
2409 #undef _
2410     default:
2411       s = format (s, "unknown");
2412       return s;
2413     }
2414   s = format (s, "%s", t);
2415   return s;
2416 }
2417
2418 u8 * format_snat_key (u8 * s, va_list * args);
2419
2420 u8 *
2421 format_session_kvp (u8 * s, va_list * args)
2422 {
2423   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2424   snat_session_key_t k;
2425
2426   k.as_u64 = v->key;
2427
2428   s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2429
2430   return s;
2431 }
2432
2433 u8 *
2434 format_static_mapping_kvp (u8 * s, va_list * args)
2435 {
2436   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2437   snat_session_key_t k;
2438
2439   k.as_u64 = v->key;
2440
2441   s = format (s, "%U static-mapping-index %llu", format_snat_key, &k, v->value);
2442
2443   return s;
2444 }
2445
2446 u8 *
2447 format_user_kvp (u8 * s, va_list * args)
2448 {
2449   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2450   snat_user_key_t k;
2451
2452   k.as_u64 = v->key;
2453
2454   s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
2455               k.fib_index, v->value);
2456
2457   return s;
2458 }
2459
2460 u8 *
2461 format_ed_session_kvp (u8 * s, va_list * args)
2462 {
2463   clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2464   nat_ed_ses_key_t k;
2465
2466   k.as_u64[0] = v->key[0];
2467   k.as_u64[1] = v->key[1];
2468
2469   s = format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2470               format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2471               format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2472               format_ip_protocol, k.proto, k.fib_index, v->value);
2473
2474   return s;
2475 }
2476
2477 static u32
2478 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2479 {
2480   snat_main_t *sm = &snat_main;
2481   u32 next_worker_index = 0;
2482   u32 hash;
2483
2484   next_worker_index = sm->first_worker_index;
2485   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2486          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2487
2488   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2489     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2490   else
2491     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2492
2493   return next_worker_index;
2494 }
2495
2496 static u32
2497 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2498 {
2499   snat_main_t *sm = &snat_main;
2500   udp_header_t *udp;
2501   u16 port;
2502   snat_session_key_t m_key;
2503   clib_bihash_kv_8_8_t kv, value;
2504   snat_static_mapping_t *m;
2505   u32 proto;
2506   u32 next_worker_index = 0;
2507
2508   /* first try static mappings without port */
2509   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2510     {
2511       m_key.addr = ip0->dst_address;
2512       m_key.port = 0;
2513       m_key.protocol = 0;
2514       m_key.fib_index = rx_fib_index0;
2515       kv.key = m_key.as_u64;
2516       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2517         {
2518           m = pool_elt_at_index (sm->static_mappings, value.value);
2519           return m->workers[0];
2520         }
2521     }
2522
2523   proto = ip_proto_to_snat_proto (ip0->protocol);
2524   udp = ip4_next_header (ip0);
2525   port = udp->dst_port;
2526
2527   if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2528     {
2529       if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2530         return vlib_get_thread_index ();
2531
2532       if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2533         {
2534           nat_reass_ip4_t *reass;
2535
2536           reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2537                                       ip0->fragment_id, ip0->protocol);
2538
2539           if (reass && (reass->thread_index != (u32) ~ 0))
2540             return reass->thread_index;
2541           else
2542             return vlib_get_thread_index ();
2543         }
2544     }
2545
2546   /* unknown protocol */
2547   if (PREDICT_FALSE (proto == ~0))
2548     {
2549       /* use current thread */
2550       return vlib_get_thread_index ();
2551     }
2552
2553   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2554     {
2555       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2556       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2557       if (!icmp_is_error_message (icmp))
2558         port = echo->identifier;
2559       else
2560         {
2561           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2562           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2563           void *l4_header = ip4_next_header (inner_ip);
2564           switch (proto)
2565             {
2566             case SNAT_PROTOCOL_ICMP:
2567               icmp = (icmp46_header_t*)l4_header;
2568               echo = (icmp_echo_header_t *)(icmp + 1);
2569               port = echo->identifier;
2570               break;
2571             case SNAT_PROTOCOL_UDP:
2572             case SNAT_PROTOCOL_TCP:
2573               port = ((tcp_udp_header_t*)l4_header)->src_port;
2574               break;
2575             default:
2576               return vlib_get_thread_index ();
2577             }
2578         }
2579     }
2580
2581   /* try static mappings with port */
2582   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2583     {
2584       m_key.addr = ip0->dst_address;
2585       m_key.port = clib_net_to_host_u16 (port);
2586       m_key.protocol = proto;
2587       m_key.fib_index = rx_fib_index0;
2588       kv.key = m_key.as_u64;
2589       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2590         {
2591           m = pool_elt_at_index (sm->static_mappings, value.value);
2592           return m->workers[0];
2593         }
2594     }
2595
2596   /* worker by outside port */
2597   next_worker_index = sm->first_worker_index;
2598   next_worker_index +=
2599     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2600   return next_worker_index;
2601 }
2602
2603 static u32
2604 nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index)
2605 {
2606   snat_main_t *sm = &snat_main;
2607   clib_bihash_kv_8_8_t kv, value;
2608   u32 proto, next_worker_index = 0;
2609   udp_header_t *udp;
2610   u16 port;
2611   snat_static_mapping_t *m;
2612   u32 hash;
2613
2614   /* first try static mappings without port */
2615   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2616     {
2617       make_sm_kv (&kv, &ip->dst_address, 0, rx_fib_index, 0);
2618       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2619         {
2620           m = pool_elt_at_index (sm->static_mappings, value.value);
2621           return m->workers[0];
2622         }
2623     }
2624
2625   proto = ip_proto_to_snat_proto (ip->protocol);
2626
2627   /* unknown protocol */
2628   if (PREDICT_FALSE (proto == ~0))
2629     {
2630       /* use current thread */
2631       return vlib_get_thread_index ();
2632     }
2633
2634   udp = ip4_next_header (ip);
2635   port = udp->dst_port;
2636
2637   if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
2638     {
2639       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2640       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2641       if (!icmp_is_error_message (icmp))
2642         port = echo->identifier;
2643       else
2644         {
2645           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2646           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2647           void *l4_header = ip4_next_header (inner_ip);
2648           switch (proto)
2649             {
2650             case SNAT_PROTOCOL_ICMP:
2651               icmp = (icmp46_header_t*)l4_header;
2652               echo = (icmp_echo_header_t *)(icmp + 1);
2653               port = echo->identifier;
2654               break;
2655             case SNAT_PROTOCOL_UDP:
2656             case SNAT_PROTOCOL_TCP:
2657               port = ((tcp_udp_header_t*)l4_header)->src_port;
2658               break;
2659             default:
2660               return vlib_get_thread_index ();
2661             }
2662         }
2663     }
2664
2665   /* try static mappings with port */
2666   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2667     {
2668       make_sm_kv (&kv, &ip->dst_address, proto, rx_fib_index,
2669                   clib_net_to_host_u16 (port));
2670       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2671         {
2672           m = pool_elt_at_index (sm->static_mappings, value.value);
2673           if (!vec_len(m->locals))
2674             return m->workers[0];
2675
2676           hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
2677                  (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >>24);
2678
2679           if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
2680             return m->workers[hash & (_vec_len (m->workers) - 1)];
2681           else
2682             return m->workers[hash % _vec_len (m->workers)];
2683         }
2684     }
2685
2686   /* worker by outside port */
2687   next_worker_index = sm->first_worker_index;
2688   next_worker_index +=
2689     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2690
2691   return next_worker_index;
2692 }
2693
2694 static clib_error_t *
2695 snat_config (vlib_main_t * vm, unformat_input_t * input)
2696 {
2697   snat_main_t * sm = &snat_main;
2698   nat66_main_t * nm = &nat66_main;
2699   u32 translation_buckets = 1024;
2700   u32 translation_memory_size = 128<<20;
2701   u32 user_buckets = 128;
2702   u32 user_memory_size = 64<<20;
2703   u32 max_translations_per_user = 100;
2704   u32 outside_vrf_id = 0;
2705   u32 outside_ip6_vrf_id = 0;
2706   u32 inside_vrf_id = 0;
2707   u32 static_mapping_buckets = 1024;
2708   u32 static_mapping_memory_size = 64<<20;
2709   u32 nat64_bib_buckets = 1024;
2710   u32 nat64_bib_memory_size = 128 << 20;
2711   u32 nat64_st_buckets = 2048;
2712   u32 nat64_st_memory_size = 256 << 20;
2713   u8 static_mapping_only = 0;
2714   u8 static_mapping_connection_tracking = 0;
2715   snat_main_per_thread_data_t *tsm;
2716   dslite_main_t * dm = &dslite_main;
2717
2718   sm->deterministic = 0;
2719   sm->out2in_dpo = 0;
2720   sm->endpoint_dependent = 0;
2721
2722   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2723     {
2724       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2725         ;
2726       else if (unformat (input, "translation hash memory %d",
2727                          &translation_memory_size));
2728       else if (unformat (input, "user hash buckets %d", &user_buckets))
2729         ;
2730       else if (unformat (input, "user hash memory %d",
2731                          &user_memory_size))
2732         ;
2733       else if (unformat (input, "max translations per user %d",
2734                          &max_translations_per_user))
2735         ;
2736       else if (unformat (input, "outside VRF id %d",
2737                          &outside_vrf_id))
2738         ;
2739       else if (unformat (input, "outside ip6 VRF id %d",
2740                          &outside_ip6_vrf_id))
2741         ;
2742       else if (unformat (input, "inside VRF id %d",
2743                          &inside_vrf_id))
2744         ;
2745       else if (unformat (input, "static mapping only"))
2746         {
2747           static_mapping_only = 1;
2748           if (unformat (input, "connection tracking"))
2749             static_mapping_connection_tracking = 1;
2750         }
2751       else if (unformat (input, "deterministic"))
2752         sm->deterministic = 1;
2753       else if (unformat (input, "nat64 bib hash buckets %d",
2754                          &nat64_bib_buckets))
2755         ;
2756       else if (unformat (input, "nat64 bib hash memory %d",
2757                          &nat64_bib_memory_size))
2758         ;
2759       else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2760         ;
2761       else if (unformat (input, "nat64 st hash memory %d",
2762                          &nat64_st_memory_size))
2763         ;
2764       else if (unformat (input, "out2in dpo"))
2765         sm->out2in_dpo = 1;
2766       else if (unformat (input, "dslite ce"))
2767         dslite_set_ce(dm, 1);
2768       else if (unformat (input, "endpoint-dependent"))
2769         sm->endpoint_dependent = 1;
2770       else
2771         return clib_error_return (0, "unknown input '%U'",
2772                                   format_unformat_error, input);
2773     }
2774
2775   /* for show commands, etc. */
2776   sm->translation_buckets = translation_buckets;
2777   sm->translation_memory_size = translation_memory_size;
2778   /* do not exceed load factor 10 */
2779   sm->max_translations = 10 * translation_buckets;
2780   sm->user_buckets = user_buckets;
2781   sm->user_memory_size = user_memory_size;
2782   sm->max_translations_per_user = max_translations_per_user;
2783   sm->outside_vrf_id = outside_vrf_id;
2784   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2785                                                              outside_vrf_id,
2786                                                              FIB_SOURCE_PLUGIN_HI);
2787   nm->outside_vrf_id = outside_ip6_vrf_id;
2788   nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2789                                                              outside_ip6_vrf_id,
2790                                                              FIB_SOURCE_PLUGIN_HI);
2791   sm->inside_vrf_id = inside_vrf_id;
2792   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2793                                                             inside_vrf_id,
2794                                                             FIB_SOURCE_PLUGIN_HI);
2795   sm->static_mapping_only = static_mapping_only;
2796   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2797
2798   nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2799                  nat64_st_memory_size);
2800
2801   if (sm->deterministic)
2802     {
2803       sm->in2out_node_index = snat_det_in2out_node.index;
2804       sm->in2out_output_node_index = ~0;
2805       sm->out2in_node_index = snat_det_out2in_node.index;
2806       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2807       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2808     }
2809   else
2810     {
2811       if (sm->endpoint_dependent)
2812         {
2813           sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2814           sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
2815           sm->in2out_node_index = nat44_ed_in2out_node.index;
2816           sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
2817           sm->out2in_node_index = nat44_ed_out2in_node.index;
2818           sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
2819           sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
2820         }
2821       else
2822         {
2823           sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2824           sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2825           sm->in2out_node_index = snat_in2out_node.index;
2826           sm->in2out_output_node_index = snat_in2out_output_node.index;
2827           sm->out2in_node_index = snat_out2in_node.index;
2828           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2829           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2830         }
2831       if (!static_mapping_only ||
2832           (static_mapping_only && static_mapping_connection_tracking))
2833         {
2834           vec_foreach (tsm, sm->per_thread_data)
2835             {
2836               if (sm->endpoint_dependent)
2837                 {
2838                   clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
2839                                          translation_buckets,
2840                                          translation_memory_size);
2841                   clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
2842                                                       format_ed_session_kvp);
2843
2844                   clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
2845                                          translation_buckets,
2846                                          translation_memory_size);
2847                   clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
2848                                                       format_ed_session_kvp);
2849                 }
2850               else
2851                 {
2852                   clib_bihash_init_8_8 (&tsm->in2out, "in2out",
2853                                         translation_buckets,
2854                                         translation_memory_size);
2855                   clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
2856                                                      format_session_kvp);
2857
2858                   clib_bihash_init_8_8 (&tsm->out2in, "out2in",
2859                                         translation_buckets,
2860                                         translation_memory_size);
2861                   clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
2862                                                      format_session_kvp);
2863                 }
2864
2865               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2866                                     user_memory_size);
2867               clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
2868                                                  format_user_kvp);
2869             }
2870
2871         }
2872       else
2873         {
2874           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2875           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2876         }
2877       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2878                             "static_mapping_by_local", static_mapping_buckets,
2879                             static_mapping_memory_size);
2880       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
2881                                          format_static_mapping_kvp);
2882
2883       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2884                             "static_mapping_by_external", static_mapping_buckets,
2885                             static_mapping_memory_size);
2886       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
2887                                          format_static_mapping_kvp);
2888     }
2889
2890   return 0;
2891 }
2892
2893 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2894
2895 u8 * format_snat_session_state (u8 * s, va_list * args)
2896 {
2897   u32 i = va_arg (*args, u32);
2898   u8 *t = 0;
2899
2900   switch (i)
2901     {
2902 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2903     foreach_snat_session_state
2904 #undef _
2905     default:
2906       t = format (t, "unknown");
2907     }
2908   s = format (s, "%s", t);
2909   return s;
2910 }
2911
2912 u8 * format_snat_key (u8 * s, va_list * args)
2913 {
2914   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2915
2916   s = format (s, "%U proto %U port %d fib %d",
2917               format_ip4_address, &key->addr,
2918               format_snat_protocol, key->protocol,
2919               clib_net_to_host_u16 (key->port), key->fib_index);
2920   return s;
2921 }
2922
2923 u8 * format_snat_session (u8 * s, va_list * args)
2924 {
2925   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2926   snat_session_t * sess = va_arg (*args, snat_session_t *);
2927
2928   if (snat_is_unk_proto_session (sess))
2929     {
2930       s = format (s, "  i2o %U proto %u fib %u\n",
2931                   format_ip4_address, &sess->in2out.addr,
2932                   clib_net_to_host_u16 (sess->in2out.port),
2933                   sess->in2out.fib_index);
2934       s = format (s, "    o2i %U proto %u fib %u\n",
2935                   format_ip4_address, &sess->out2in.addr,
2936                   clib_net_to_host_u16 (sess->out2in.port),
2937                   sess->out2in.fib_index);
2938     }
2939   else
2940     {
2941       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
2942       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
2943     }
2944   if (is_ed_session (sess) || is_fwd_bypass_session (sess))
2945     {
2946       if (is_twice_nat_session (sess))
2947         {
2948           s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
2949                       format_ip4_address, &sess->ext_host_addr,
2950                       clib_net_to_host_u16 (sess->ext_host_port),
2951                       format_ip4_address, &sess->ext_host_nat_addr,
2952                       clib_net_to_host_u16 (sess->ext_host_nat_port));
2953         }
2954       else
2955         {
2956           if (sess->ext_host_addr.as_u32)
2957               s = format (s, "       external host %U:%u\n",
2958                           format_ip4_address, &sess->ext_host_addr,
2959                           clib_net_to_host_u16 (sess->ext_host_port));
2960         }
2961     }
2962   s = format (s, "       index %llu\n", sess - sm->sessions);
2963   s = format (s, "       last heard %.2f\n", sess->last_heard);
2964   s = format (s, "       total pkts %d, total bytes %lld\n",
2965               sess->total_pkts, sess->total_bytes);
2966   if (snat_is_session_static (sess))
2967     s = format (s, "       static translation\n");
2968   else
2969     s = format (s, "       dynamic translation\n");
2970   if (is_fwd_bypass_session (sess))
2971     s = format (s, "       forwarding-bypass\n");
2972   if (is_lb_session (sess))
2973     s = format (s, "       load-balancing\n");
2974   if (is_twice_nat_session (sess))
2975     s = format (s, "       twice-nat\n");
2976
2977   return s;
2978 }
2979
2980 u8 * format_snat_user (u8 * s, va_list * args)
2981 {
2982   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2983   snat_user_t * u = va_arg (*args, snat_user_t *);
2984   int verbose = va_arg (*args, int);
2985   dlist_elt_t * head, * elt;
2986   u32 elt_index, head_index;
2987   u32 session_index;
2988   snat_session_t * sess;
2989
2990   s = format (s, "%U: %d dynamic translations, %d static translations\n",
2991               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2992
2993   if (verbose == 0)
2994     return s;
2995
2996   if (u->nsessions || u->nstaticsessions)
2997     {
2998       head_index = u->sessions_per_user_list_head_index;
2999       head = pool_elt_at_index (sm->list_pool, head_index);
3000
3001       elt_index = head->next;
3002       elt = pool_elt_at_index (sm->list_pool, elt_index);
3003       session_index = elt->value;
3004
3005       while (session_index != ~0)
3006         {
3007           sess = pool_elt_at_index (sm->sessions, session_index);
3008
3009           s = format (s, "  %U\n", format_snat_session, sm, sess);
3010
3011           elt_index = elt->next;
3012           elt = pool_elt_at_index (sm->list_pool, elt_index);
3013           session_index = elt->value;
3014         }
3015     }
3016
3017   return s;
3018 }
3019
3020 u8 * format_snat_static_mapping (u8 * s, va_list * args)
3021 {
3022   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
3023   nat44_lb_addr_port_t *local;
3024
3025   if (m->addr_only)
3026       s = format (s, "local %U external %U vrf %d %s %s",
3027                   format_ip4_address, &m->local_addr,
3028                   format_ip4_address, &m->external_addr,
3029                   m->vrf_id,
3030                   m->twice_nat == TWICE_NAT ? "twice-nat" :
3031                   m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
3032                   m->out2in_only ? "out2in-only" : "");
3033   else
3034    {
3035       if (vec_len (m->locals))
3036         {
3037           s = format (s, "%U vrf %d external %U:%d %s %s",
3038                       format_snat_protocol, m->proto,
3039                       m->vrf_id,
3040                       format_ip4_address, &m->external_addr, m->external_port,
3041                       m->twice_nat == TWICE_NAT ? "twice-nat" :
3042                       m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
3043                       m->out2in_only ? "out2in-only" : "");
3044           vec_foreach (local, m->locals)
3045             s = format (s, "\n  local %U:%d probability %d\%",
3046                         format_ip4_address, &local->addr, local->port,
3047                         local->probability);
3048         }
3049       else
3050         s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
3051                     format_snat_protocol, m->proto,
3052                     format_ip4_address, &m->local_addr, m->local_port,
3053                     format_ip4_address, &m->external_addr, m->external_port,
3054                     m->vrf_id,
3055                     m->twice_nat == TWICE_NAT ? "twice-nat" :
3056                     m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
3057                     m->out2in_only ? "out2in-only" : "");
3058    }
3059   return s;
3060 }
3061
3062 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
3063 {
3064   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
3065   vnet_main_t *vnm = vnet_get_main();
3066
3067   if (m->addr_only)
3068       s = format (s, "local %U external %U vrf %d",
3069                   format_ip4_address, &m->l_addr,
3070                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
3071                   m->vrf_id);
3072   else
3073       s = format (s, "%U local %U:%d external %U:%d vrf %d",
3074                   format_snat_protocol, m->proto,
3075                   format_ip4_address, &m->l_addr, m->l_port,
3076                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
3077                   m->e_port, m->vrf_id);
3078
3079   return s;
3080 }
3081
3082 u8 * format_det_map_ses (u8 * s, va_list * args)
3083 {
3084   snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
3085   ip4_address_t in_addr, out_addr;
3086   u32 in_offset, out_offset;
3087   snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
3088   u32 * i = va_arg (*args, u32 *);
3089
3090   u32 user_index = *i / SNAT_DET_SES_PER_USER;
3091   in_addr.as_u32 = clib_host_to_net_u32 (
3092     clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
3093   in_offset = clib_net_to_host_u32(in_addr.as_u32) -
3094     clib_net_to_host_u32(det_map->in_addr.as_u32);
3095   out_offset = in_offset / det_map->sharing_ratio;
3096   out_addr.as_u32 = clib_host_to_net_u32(
3097     clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
3098   s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
3099               format_ip4_address, &in_addr,
3100               clib_net_to_host_u16 (ses->in_port),
3101               format_ip4_address, &out_addr,
3102               clib_net_to_host_u16 (ses->out.out_port),
3103               format_ip4_address, &ses->out.ext_host_addr,
3104               clib_net_to_host_u16 (ses->out.ext_host_port),
3105               format_snat_session_state, ses->state,
3106               ses->expire);
3107
3108   return s;
3109 }
3110
3111 static void
3112 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
3113                                  uword opaque,
3114                                  u32 sw_if_index,
3115                                  ip4_address_t * address,
3116                                  u32 address_length,
3117                                  u32 if_address_index,
3118                                  u32 is_delete)
3119 {
3120   snat_main_t *sm = &snat_main;
3121   snat_static_map_resolve_t *rp;
3122   snat_static_mapping_t *m;
3123   snat_session_key_t m_key;
3124   clib_bihash_kv_8_8_t kv, value;
3125   int i, rv;
3126   ip4_address_t l_addr;
3127
3128   for (i = 0; i < vec_len (sm->to_resolve); i++)
3129     {
3130       rp = sm->to_resolve + i;
3131       if (rp->addr_only == 0)
3132         continue;
3133       if (rp->sw_if_index == sw_if_index)
3134         goto match;
3135     }
3136
3137   return;
3138
3139 match:
3140   m_key.addr.as_u32 = address->as_u32;
3141   m_key.port = rp->addr_only ? 0 : rp->e_port;
3142   m_key.protocol = rp->addr_only ? 0 : rp->proto;
3143   m_key.fib_index = sm->outside_fib_index;
3144   kv.key = m_key.as_u64;
3145   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
3146     m = 0;
3147   else
3148     m = pool_elt_at_index (sm->static_mappings, value.value);
3149
3150   if (!is_delete)
3151     {
3152       /* Don't trip over lease renewal, static config */
3153       if (m)
3154         return;
3155     }
3156   else
3157     {
3158       if (!m)
3159         return;
3160     }
3161
3162   /* Indetity mapping? */
3163   if (rp->l_addr.as_u32 == 0)
3164     l_addr.as_u32 = address[0].as_u32;
3165   else
3166     l_addr.as_u32 = rp->l_addr.as_u32;
3167   /* Add the static mapping */
3168   rv = snat_add_static_mapping (l_addr,
3169                                 address[0],
3170                                 rp->l_port,
3171                                 rp->e_port,
3172                                 rp->vrf_id,
3173                                 rp->addr_only,
3174                                 ~0 /* sw_if_index */,
3175                                 rp->proto,
3176                                 !is_delete,
3177                                 0, 0, rp->tag);
3178   if (rv)
3179     nat_log_notice ("snat_add_static_mapping returned %d", rv);
3180 }
3181
3182 static void
3183 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3184                                        uword opaque,
3185                                        u32 sw_if_index,
3186                                        ip4_address_t * address,
3187                                        u32 address_length,
3188                                        u32 if_address_index,
3189                                        u32 is_delete)
3190 {
3191   snat_main_t *sm = &snat_main;
3192   snat_static_map_resolve_t *rp;
3193   ip4_address_t l_addr;
3194   int i, j;
3195   int rv;
3196   u8 twice_nat = 0;
3197   snat_address_t *addresses = sm->addresses;
3198
3199   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3200     {
3201       if (sw_if_index == sm->auto_add_sw_if_indices[i])
3202           goto match;
3203     }
3204
3205   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
3206     {
3207       twice_nat = 1;
3208       addresses = sm->twice_nat_addresses;
3209       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3210           goto match;
3211     }
3212
3213   return;
3214
3215 match:
3216   if (!is_delete)
3217     {
3218       /* Don't trip over lease renewal, static config */
3219       for (j = 0; j < vec_len(addresses); j++)
3220         if (addresses[j].addr.as_u32 == address->as_u32)
3221           return;
3222
3223       (void) snat_add_address (sm, address, ~0, twice_nat);
3224       /* Scan static map resolution vector */
3225       for (j = 0; j < vec_len (sm->to_resolve); j++)
3226         {
3227           rp = sm->to_resolve + j;
3228           if (rp->addr_only)
3229             continue;
3230           /* On this interface? */
3231           if (rp->sw_if_index == sw_if_index)
3232             {
3233               /* Indetity mapping? */
3234               if (rp->l_addr.as_u32 == 0)
3235                 l_addr.as_u32 = address[0].as_u32;
3236               else
3237                 l_addr.as_u32 = rp->l_addr.as_u32;
3238               /* Add the static mapping */
3239               rv = snat_add_static_mapping (l_addr,
3240                                             address[0],
3241                                             rp->l_port,
3242                                             rp->e_port,
3243                                             rp->vrf_id,
3244                                             rp->addr_only,
3245                                             ~0 /* sw_if_index */,
3246                                             rp->proto,
3247                                             rp->is_add,
3248                                             0, 0, rp->tag);
3249               if (rv)
3250                 nat_log_notice ("snat_add_static_mapping returned %d", rv);
3251             }
3252         }
3253       return;
3254     }
3255   else
3256     {
3257       (void) snat_del_address(sm, address[0], 1, twice_nat);
3258       return;
3259     }
3260 }
3261
3262
3263 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
3264                                 u8 twice_nat)
3265 {
3266   ip4_main_t * ip4_main = sm->ip4_main;
3267   ip4_address_t * first_int_addr;
3268   snat_static_map_resolve_t *rp;
3269   u32 *indices_to_delete = 0;
3270   int i, j;
3271   u32 *auto_add_sw_if_indices =
3272     twice_nat ? sm->auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3273
3274   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3275                                                 0 /* just want the address*/);
3276
3277   for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
3278     {
3279       if (auto_add_sw_if_indices[i] == sw_if_index)
3280         {
3281           if (is_del)
3282             {
3283               /* if have address remove it */
3284               if (first_int_addr)
3285                   (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3286               else
3287                 {
3288                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3289                     {
3290                       rp = sm->to_resolve + j;
3291                       if (rp->sw_if_index == sw_if_index)
3292                         vec_add1 (indices_to_delete, j);
3293                     }
3294                   if (vec_len(indices_to_delete))
3295                     {
3296                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3297                         vec_del1(sm->to_resolve, j);
3298                       vec_free(indices_to_delete);
3299                     }
3300                 }
3301               if (twice_nat)
3302                 vec_del1(sm->auto_add_sw_if_indices_twice_nat, i);
3303               else
3304                 vec_del1(sm->auto_add_sw_if_indices, i);
3305             }
3306           else
3307             return VNET_API_ERROR_VALUE_EXIST;
3308
3309           return 0;
3310         }
3311     }
3312
3313   if (is_del)
3314     return VNET_API_ERROR_NO_SUCH_ENTRY;
3315
3316   /* add to the auto-address list */
3317   if (twice_nat)
3318     vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3319   else
3320     vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3321
3322   /* If the address is already bound - or static - add it now */
3323   if (first_int_addr)
3324       (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
3325
3326   return 0;
3327 }
3328
3329 int
3330 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3331                    snat_protocol_t proto, u32 vrf_id, int is_in)
3332 {
3333   snat_main_per_thread_data_t *tsm;
3334   clib_bihash_kv_8_8_t kv, value;
3335   ip4_header_t ip;
3336   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3337   snat_session_key_t key;
3338   snat_session_t *s;
3339   clib_bihash_8_8_t *t;
3340
3341   if (sm->endpoint_dependent)
3342     return VNET_API_ERROR_UNSUPPORTED;
3343
3344   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3345   if (sm->num_workers > 1)
3346     tsm =
3347       vec_elt_at_index (sm->per_thread_data,
3348                         sm->worker_in2out_cb (&ip, fib_index));
3349   else
3350     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3351
3352   key.addr.as_u32 = addr->as_u32;
3353   key.port = clib_host_to_net_u16 (port);
3354   key.protocol = proto;
3355   key.fib_index = fib_index;
3356   kv.key = key.as_u64;
3357   t = is_in ? &tsm->in2out : &tsm->out2in;
3358   if (!clib_bihash_search_8_8 (t, &kv, &value))
3359     {
3360       if (pool_is_free_index (tsm->sessions, value.value))
3361         return VNET_API_ERROR_UNSPECIFIED;
3362
3363       s = pool_elt_at_index (tsm->sessions, value.value);
3364       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3365       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3366       return 0;
3367     }
3368
3369   return VNET_API_ERROR_NO_SUCH_ENTRY;
3370 }
3371
3372 int
3373 nat44_del_ed_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3374                       ip4_address_t *eh_addr, u16 eh_port, u8 proto,
3375                       u32 vrf_id, int is_in)
3376 {
3377   ip4_header_t ip;
3378   clib_bihash_16_8_t *t;
3379   nat_ed_ses_key_t key;
3380   clib_bihash_kv_16_8_t kv, value;
3381   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3382   snat_session_t *s;
3383   snat_main_per_thread_data_t *tsm;
3384
3385   if (!sm->endpoint_dependent)
3386     return VNET_API_ERROR_FEATURE_DISABLED;
3387
3388   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3389   if (sm->num_workers > 1)
3390     tsm =
3391       vec_elt_at_index (sm->per_thread_data,
3392                         sm->worker_in2out_cb (&ip, fib_index));
3393   else
3394     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3395
3396   t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
3397   key.l_addr.as_u32 = addr->as_u32;
3398   key.r_addr.as_u32 = eh_addr->as_u32;
3399   key.l_port = clib_host_to_net_u16 (port);
3400   key.r_port = clib_host_to_net_u16 (eh_port);
3401   key.proto = proto;
3402   key.fib_index = clib_host_to_net_u32 (fib_index);
3403   kv.key[0] = key.as_u64[0];
3404   kv.key[1] = key.as_u64[1];
3405   if (clib_bihash_search_16_8 (t, &kv, &value))
3406     return VNET_API_ERROR_NO_SUCH_ENTRY;
3407
3408   if (pool_is_free_index (tsm->sessions, value.value))
3409     return VNET_API_ERROR_UNSPECIFIED;
3410   s = pool_elt_at_index (tsm->sessions, value.value);
3411   nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3412   nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3413   return 0;
3414 }
3415
3416 void
3417 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
3418 {
3419   snat_main_t *sm = &snat_main;
3420
3421   sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3422   sm->psid = psid;
3423   sm->psid_offset = psid_offset;
3424   sm->psid_length = psid_length;
3425 }
3426
3427 void
3428 nat_set_alloc_addr_and_port_default (void)
3429 {
3430   snat_main_t *sm = &snat_main;
3431
3432   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3433 }
3434