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