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