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