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