nat: fixing cli bug for nat44-ei and nat44-ed
[vpp.git] / src / plugins / nat / nat44-ed / nat44_ed_cli.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT44 CLI
18  */
19
20 #include <vnet/fib/fib_table.h>
21
22 #include <nat/lib/log.h>
23 #include <nat/lib/nat_inlines.h>
24 #include <nat/lib/ipfix_logging.h>
25
26 #include <nat/nat44-ed/nat44_ed.h>
27 #include <nat/nat44-ed/nat44_ed_inlines.h>
28 #include <nat/nat44-ed/nat44_ed_affinity.h>
29
30 static clib_error_t *
31 nat44_enable_command_fn (vlib_main_t * vm,
32                          unformat_input_t * input, vlib_cli_command_t * cmd)
33 {
34   snat_main_t *sm = &snat_main;
35   unformat_input_t _line_input, *line_input = &_line_input;
36   clib_error_t *error = 0;
37
38   nat44_config_t c = { 0 };
39   u8 mode_set = 0;
40
41   if (sm->enabled)
42     return clib_error_return (0, "nat44 already enabled");
43
44   /* Get a line of input. */
45   if (!unformat_user (input, unformat_line_input, line_input))
46     {
47       if (nat44_plugin_enable (c) != 0)
48         return clib_error_return (0, "nat44 enable failed");
49       return 0;
50     }
51
52   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
53     {
54       if (!mode_set && unformat (line_input, "static-mapping-only"))
55         {
56           mode_set = 1;
57           c.static_mapping_only = 1;
58           if (unformat (line_input, "connection-tracking"))
59             {
60               c.connection_tracking = 1;
61             }
62         }
63       else if (unformat (line_input, "inside-vrf %u", &c.inside_vrf));
64       else if (unformat (line_input, "outside-vrf %u", &c.outside_vrf));
65       else if (unformat (line_input, "sessions %u", &c.sessions));
66       else
67         {
68           error = clib_error_return (0, "unknown input '%U'",
69                                      format_unformat_error, line_input);
70           goto done;
71         }
72     }
73
74   if (!c.sessions)
75     {
76       error = clib_error_return (0, "number of sessions is required");
77       goto done;
78     }
79
80   if (nat44_plugin_enable (c) != 0)
81     error = clib_error_return (0, "nat44 enable failed");
82 done:
83   unformat_free (line_input);
84   return error;
85 }
86
87 static clib_error_t *
88 nat44_disable_command_fn (vlib_main_t * vm,
89                           unformat_input_t * input, vlib_cli_command_t * cmd)
90 {
91   snat_main_t *sm = &snat_main;
92   clib_error_t *error = 0;
93
94   if (!sm->enabled)
95     return clib_error_return (0, "nat44 already disabled");
96
97   if (nat44_plugin_disable () != 0)
98     error = clib_error_return (0, "nat44 disable failed");
99
100   return error;
101 }
102
103 static clib_error_t *
104 set_workers_command_fn (vlib_main_t * vm,
105                         unformat_input_t * input, vlib_cli_command_t * cmd)
106 {
107   unformat_input_t _line_input, *line_input = &_line_input;
108   uword *bitmap = 0;
109   int rv = 0;
110   clib_error_t *error = 0;
111
112   /* Get a line of input. */
113   if (!unformat_user (input, unformat_line_input, line_input))
114     return 0;
115
116   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
117     {
118       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
119         ;
120       else
121         {
122           error = clib_error_return (0, "unknown input '%U'",
123                                      format_unformat_error, line_input);
124           goto done;
125         }
126     }
127
128   if (bitmap == 0)
129     {
130       error = clib_error_return (0, "List of workers must be specified.");
131       goto done;
132     }
133
134   rv = snat_set_workers (bitmap);
135
136   clib_bitmap_free (bitmap);
137
138   switch (rv)
139     {
140     case VNET_API_ERROR_INVALID_WORKER:
141       error = clib_error_return (0, "Invalid worker(s).");
142       goto done;
143     case VNET_API_ERROR_FEATURE_DISABLED:
144       error = clib_error_return (0,
145                                  "Supported only if 2 or more workes available.");
146       goto done;
147     default:
148       break;
149     }
150
151 done:
152   unformat_free (line_input);
153
154   return error;
155 }
156
157 static clib_error_t *
158 nat_show_workers_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
159                              vlib_cli_command_t * cmd)
160 {
161   snat_main_t *sm = &snat_main;
162   u32 *worker;
163
164   if (sm->num_workers > 1)
165     {
166       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
167       vec_foreach (worker, sm->workers)
168         {
169           vlib_worker_thread_t *w =
170             vlib_worker_threads + *worker + sm->first_worker_index;
171           vlib_cli_output (vm, "  %s", w->name);
172         }
173     }
174
175   return 0;
176 }
177
178 static clib_error_t *
179 snat_set_log_level_command_fn (vlib_main_t * vm,
180                                unformat_input_t * input,
181                                vlib_cli_command_t * cmd)
182 {
183   unformat_input_t _line_input, *line_input = &_line_input;
184   snat_main_t *sm = &snat_main;
185   u8 log_level = NAT_LOG_NONE;
186   clib_error_t *error = 0;
187
188   /* Get a line of input. */
189   if (!unformat_user (input, unformat_line_input, line_input))
190     return 0;
191
192   if (!unformat (line_input, "%d", &log_level))
193     {
194       error = clib_error_return (0, "unknown input '%U'",
195                                  format_unformat_error, line_input);
196       goto done;
197     }
198   if (log_level > NAT_LOG_DEBUG)
199     {
200       error = clib_error_return (0, "unknown logging level '%d'", log_level);
201       goto done;
202     }
203   sm->log_level = log_level;
204
205 done:
206   unformat_free (line_input);
207
208   return error;
209 }
210
211 static clib_error_t *
212 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
213                                               unformat_input_t * input,
214                                               vlib_cli_command_t * cmd)
215 {
216   unformat_input_t _line_input, *line_input = &_line_input;
217   u32 domain_id = 0;
218   u32 src_port = 0;
219   u8 enable = 1;
220   int rv = 0;
221   clib_error_t *error = 0;
222
223   /* Get a line of input. */
224   if (!unformat_user (input, unformat_line_input, line_input))
225     {
226       rv = nat_ipfix_logging_enable_disable (enable, domain_id,
227                                              (u16) src_port);
228       if (rv)
229         return clib_error_return (0, "ipfix logging enable failed");
230       return 0;
231     }
232
233   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
234     {
235       if (unformat (line_input, "domain %d", &domain_id))
236         ;
237       else if (unformat (line_input, "src-port %d", &src_port))
238         ;
239       else if (unformat (line_input, "disable"))
240         enable = 0;
241       else
242         {
243           error = clib_error_return (0, "unknown input '%U'",
244                                      format_unformat_error, line_input);
245           goto done;
246         }
247     }
248
249   rv = nat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
250
251   if (rv)
252     {
253       error = clib_error_return (0, "ipfix logging enable failed");
254       goto done;
255     }
256
257 done:
258   unformat_free (line_input);
259
260   return error;
261 }
262
263 static clib_error_t *
264 nat44_show_hash_command_fn (vlib_main_t * vm, unformat_input_t * input,
265                             vlib_cli_command_t * cmd)
266 {
267   snat_main_t *sm = &snat_main;
268   nat_affinity_main_t *nam = &nat_affinity_main;
269   int i;
270   int verbose = 0;
271
272   if (unformat (input, "detail"))
273     verbose = 1;
274   else if (unformat (input, "verbose"))
275     verbose = 2;
276
277   vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->static_mapping_by_local,
278                    verbose);
279   vlib_cli_output (vm, "%U",
280                    format_bihash_8_8, &sm->static_mapping_by_external,
281                    verbose);
282       vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose);
283   vec_foreach_index (i, sm->per_thread_data)
284   {
285     vlib_cli_output (vm, "-------- thread %d %s --------\n",
286                      i, vlib_worker_threads[i].name);
287     vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose);
288   }
289
290       vlib_cli_output (vm, "%U", format_bihash_16_8, &nam->affinity_hash,
291                        verbose);
292
293   vlib_cli_output (vm, "-------- hash table parameters --------\n");
294   vlib_cli_output (vm, "translation buckets: %u", sm->translation_buckets);
295   return 0;
296 }
297
298 static clib_error_t *
299 nat_set_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input,
300                                  vlib_cli_command_t * cmd)
301 {
302   unformat_input_t _line_input, *line_input = &_line_input;
303   snat_main_t *sm = &snat_main;
304   clib_error_t *error = 0;
305   u32 mss;
306
307   /* Get a line of input. */
308   if (!unformat_user (input, unformat_line_input, line_input))
309     return 0;
310
311   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
312     {
313       if (unformat (line_input, "disable"))
314         sm->mss_clamping = 0;
315       else if (unformat (line_input, "%d", &mss))
316         sm->mss_clamping = (u16) mss;
317       else
318         {
319           error = clib_error_return (0, "unknown input '%U'",
320                                      format_unformat_error, line_input);
321           goto done;
322         }
323     }
324
325 done:
326   unformat_free (line_input);
327
328   return error;
329 }
330
331 static clib_error_t *
332 nat_show_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input,
333                                   vlib_cli_command_t * cmd)
334 {
335   snat_main_t *sm = &snat_main;
336
337   if (sm->mss_clamping)
338     vlib_cli_output (vm, "mss-clamping %d", sm->mss_clamping);
339   else
340     vlib_cli_output (vm, "mss-clamping disabled");
341
342   return 0;
343 }
344
345 static clib_error_t *
346 add_address_command_fn (vlib_main_t * vm,
347                         unformat_input_t * input, vlib_cli_command_t * cmd)
348 {
349   unformat_input_t _line_input, *line_input = &_line_input;
350   snat_main_t *sm = &snat_main;
351   ip4_address_t start_addr, end_addr, this_addr;
352   u32 start_host_order, end_host_order;
353   u32 vrf_id = ~0;
354   int i, count;
355   int is_add = 1;
356   int rv = 0;
357   clib_error_t *error = 0;
358   u8 twice_nat = 0;
359
360   /* Get a line of input. */
361   if (!unformat_user (input, unformat_line_input, line_input))
362     return 0;
363
364   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
365     {
366       if (unformat (line_input, "%U - %U",
367                     unformat_ip4_address, &start_addr,
368                     unformat_ip4_address, &end_addr))
369         ;
370       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
371         ;
372       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
373         end_addr = start_addr;
374       else if (unformat (line_input, "twice-nat"))
375         twice_nat = 1;
376       else if (unformat (line_input, "del"))
377         is_add = 0;
378       else
379         {
380           error = clib_error_return (0, "unknown input '%U'",
381                                      format_unformat_error, line_input);
382           goto done;
383         }
384     }
385
386   if (sm->static_mapping_only)
387     {
388       error = clib_error_return (0, "static mapping only mode");
389       goto done;
390     }
391
392   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
393   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
394
395   if (end_host_order < start_host_order)
396     {
397       error = clib_error_return (0, "end address less than start address");
398       goto done;
399     }
400
401   count = (end_host_order - start_host_order) + 1;
402
403   if (count > 1024)
404     nat_log_info ("%U - %U, %d addresses...",
405                   format_ip4_address, &start_addr,
406                   format_ip4_address, &end_addr, count);
407
408   this_addr = start_addr;
409
410   for (i = 0; i < count; i++)
411     {
412       if (is_add)
413         rv = snat_add_address (sm, &this_addr, vrf_id, twice_nat);
414       else
415         rv = snat_del_address (sm, this_addr, 0, twice_nat);
416
417       switch (rv)
418         {
419         case VNET_API_ERROR_VALUE_EXIST:
420           error = clib_error_return (0, "NAT address already in use.");
421           goto done;
422         case VNET_API_ERROR_NO_SUCH_ENTRY:
423           error = clib_error_return (0, "NAT address not exist.");
424           goto done;
425         case VNET_API_ERROR_UNSPECIFIED:
426           error =
427             clib_error_return (0, "NAT address used in static mapping.");
428           goto done;
429         default:
430           break;
431         }
432
433       increment_v4_address (&this_addr);
434     }
435
436 done:
437   unformat_free (line_input);
438
439   return error;
440 }
441
442 static void
443 nat44_show_lru_summary (vlib_main_t * vm, snat_main_per_thread_data_t * tsm,
444                         u64 now, u64 sess_timeout_time)
445 {
446   snat_main_t *sm = &snat_main;
447   dlist_elt_t *oldest_elt;
448   snat_session_t *s;
449   u32 oldest_index;
450
451   if (tsm->lru_pool)
452     {
453 #define _(n, d)                                                               \
454   oldest_index =                                                              \
455     clib_dlist_remove_head (tsm->lru_pool, tsm->n##_lru_head_index);          \
456   if (~0 != oldest_index)                                                     \
457     {                                                                         \
458       oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);           \
459       s = pool_elt_at_index (tsm->sessions, oldest_elt->value);               \
460       sess_timeout_time =                                                     \
461         s->last_heard + (f64) nat44_session_get_timeout (sm, s);              \
462       vlib_cli_output (vm, d " LRU min session timeout %llu (now %llu)",      \
463                        sess_timeout_time, now);                               \
464       clib_dlist_addhead (tsm->lru_pool, tsm->n##_lru_head_index,             \
465                           oldest_index);                                      \
466     }
467       _ (tcp_estab, "established tcp");
468       _ (tcp_trans, "transitory tcp");
469       _ (udp, "udp");
470       _ (unk_proto, "unknown protocol");
471       _ (icmp, "icmp");
472 #undef _
473     }
474 }
475
476 static clib_error_t *
477 nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
478                                vlib_cli_command_t * cmd)
479 {
480   snat_main_per_thread_data_t *tsm;
481   snat_main_t *sm = &snat_main;
482   snat_session_t *s;
483
484   u32 count = 0;
485
486   u64 now = vlib_time_now (vm);
487   u64 sess_timeout_time = 0;
488
489   u32 udp_sessions = 0;
490   u32 tcp_sessions = 0;
491   u32 icmp_sessions = 0;
492
493   u32 timed_out = 0;
494   u32 transitory = 0;
495   u32 transitory_wait_closed = 0;
496   u32 transitory_closed = 0;
497   u32 established = 0;
498
499   u32 fib;
500
501   for (fib = 0; fib < vec_len (sm->max_translations_per_fib); fib++)
502     vlib_cli_output (vm, "max translations per thread: %u fib %u",
503                      sm->max_translations_per_fib[fib], fib);
504
505   if (sm->num_workers > 1)
506     {
507       vec_foreach (tsm, sm->per_thread_data)
508         {
509           pool_foreach (s, tsm->sessions)
510            {
511             sess_timeout_time = s->last_heard +
512               (f64) nat44_session_get_timeout (sm, s);
513             if (now >= sess_timeout_time)
514               timed_out++;
515
516             switch (s->nat_proto)
517               {
518               case NAT_PROTOCOL_ICMP:
519                 icmp_sessions++;
520                 break;
521               case NAT_PROTOCOL_TCP:
522                 tcp_sessions++;
523                 if (s->state)
524                   {
525                     if (s->tcp_closed_timestamp)
526                       {
527                         if (now >= s->tcp_closed_timestamp)
528                           {
529                             ++transitory_closed;
530                           }
531                         else
532                           {
533                             ++transitory_wait_closed;
534                           }
535                       }
536                     transitory++;
537                   }
538                 else
539                   established++;
540                 break;
541               case NAT_PROTOCOL_UDP:
542               default:
543                 udp_sessions++;
544                 break;
545               }
546           }
547           nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
548           count += pool_elts (tsm->sessions);
549         }
550     }
551   else
552     {
553       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
554       pool_foreach (s, tsm->sessions)
555        {
556         sess_timeout_time = s->last_heard +
557             (f64) nat44_session_get_timeout (sm, s);
558         if (now >= sess_timeout_time)
559           timed_out++;
560
561         switch (s->nat_proto)
562           {
563           case NAT_PROTOCOL_ICMP:
564             icmp_sessions++;
565             break;
566           case NAT_PROTOCOL_TCP:
567             tcp_sessions++;
568             if (s->state)
569               {
570                 if (s->tcp_closed_timestamp)
571                   {
572                     if (now >= s->tcp_closed_timestamp)
573                       {
574                         ++transitory_closed;
575                       }
576                     else
577                       {
578                         ++transitory_wait_closed;
579                       }
580                   }
581                 transitory++;
582               }
583             else
584               established++;
585             break;
586           case NAT_PROTOCOL_UDP:
587           default:
588             udp_sessions++;
589             break;
590           }
591       }
592       nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
593       count = pool_elts (tsm->sessions);
594     }
595
596   vlib_cli_output (vm, "total timed out sessions: %u", timed_out);
597   vlib_cli_output (vm, "total sessions: %u", count);
598   vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions);
599   vlib_cli_output (vm, "total tcp established sessions: %u", established);
600   vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory);
601   vlib_cli_output (vm, "total tcp transitory (WAIT-CLOSED) sessions: %u",
602                    transitory_wait_closed);
603   vlib_cli_output (vm, "total tcp transitory (CLOSED) sessions: %u",
604                    transitory_closed);
605   vlib_cli_output (vm, "total udp sessions: %u", udp_sessions);
606   vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions);
607   return 0;
608 }
609
610 static clib_error_t *
611 nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
612                                  vlib_cli_command_t * cmd)
613 {
614   snat_main_t *sm = &snat_main;
615   snat_address_t *ap;
616
617   vlib_cli_output (vm, "NAT44 pool addresses:");
618   vec_foreach (ap, sm->addresses)
619     {
620       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
621       if (ap->fib_index != ~0)
622           vlib_cli_output (vm, "  tenant VRF: %u",
623             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
624       else
625         vlib_cli_output (vm, "  tenant VRF independent");
626     #define _(N, i, n, s) \
627       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
628       foreach_nat_protocol
629     #undef _
630     }
631   vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
632   vec_foreach (ap, sm->twice_nat_addresses)
633     {
634       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
635       if (ap->fib_index != ~0)
636           vlib_cli_output (vm, "  tenant VRF: %u",
637             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
638       else
639         vlib_cli_output (vm, "  tenant VRF independent");
640     #define _(N, i, n, s) \
641       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
642       foreach_nat_protocol
643     #undef _
644     }
645   return 0;
646 }
647
648 static clib_error_t *
649 snat_feature_command_fn (vlib_main_t * vm,
650                          unformat_input_t * input, vlib_cli_command_t * cmd)
651 {
652   unformat_input_t _line_input, *line_input = &_line_input;
653   vnet_main_t *vnm = vnet_get_main ();
654   clib_error_t *error = 0;
655   u32 sw_if_index;
656   u32 *inside_sw_if_indices = 0;
657   u32 *outside_sw_if_indices = 0;
658   u8 is_output_feature = 0;
659   int is_del = 0;
660   int i;
661
662   sw_if_index = ~0;
663
664   /* Get a line of input. */
665   if (!unformat_user (input, unformat_line_input, line_input))
666     return 0;
667
668   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
669     {
670       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
671                     vnm, &sw_if_index))
672         vec_add1 (inside_sw_if_indices, sw_if_index);
673       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
674                          vnm, &sw_if_index))
675         vec_add1 (outside_sw_if_indices, sw_if_index);
676       else if (unformat (line_input, "output-feature"))
677         is_output_feature = 1;
678       else if (unformat (line_input, "del"))
679         is_del = 1;
680       else
681         {
682           error = clib_error_return (0, "unknown input '%U'",
683                                      format_unformat_error, line_input);
684           goto done;
685         }
686     }
687
688   if (vec_len (inside_sw_if_indices))
689     {
690       for (i = 0; i < vec_len (inside_sw_if_indices); i++)
691         {
692           sw_if_index = inside_sw_if_indices[i];
693           if (is_output_feature)
694             {
695               if (snat_interface_add_del_output_feature
696                   (sw_if_index, 1, is_del))
697                 {
698                   error = clib_error_return (0, "%s %U failed",
699                                              is_del ? "del" : "add",
700                                              format_vnet_sw_if_index_name,
701                                              vnm, sw_if_index);
702                   goto done;
703                 }
704             }
705           else
706             {
707               if (snat_interface_add_del (sw_if_index, 1, is_del))
708                 {
709                   error = clib_error_return (0, "%s %U failed",
710                                              is_del ? "del" : "add",
711                                              format_vnet_sw_if_index_name,
712                                              vnm, sw_if_index);
713                   goto done;
714                 }
715             }
716         }
717     }
718
719   if (vec_len (outside_sw_if_indices))
720     {
721       for (i = 0; i < vec_len (outside_sw_if_indices); i++)
722         {
723           sw_if_index = outside_sw_if_indices[i];
724           if (is_output_feature)
725             {
726               if (snat_interface_add_del_output_feature
727                   (sw_if_index, 0, is_del))
728                 {
729                   error = clib_error_return (0, "%s %U failed",
730                                              is_del ? "del" : "add",
731                                              format_vnet_sw_if_index_name,
732                                              vnm, sw_if_index);
733                   goto done;
734                 }
735             }
736           else
737             {
738               if (snat_interface_add_del (sw_if_index, 0, is_del))
739                 {
740                   error = clib_error_return (0, "%s %U failed",
741                                              is_del ? "del" : "add",
742                                              format_vnet_sw_if_index_name,
743                                              vnm, sw_if_index);
744                   goto done;
745                 }
746             }
747         }
748     }
749
750 done:
751   unformat_free (line_input);
752   vec_free (inside_sw_if_indices);
753   vec_free (outside_sw_if_indices);
754
755   return error;
756 }
757
758 static clib_error_t *
759 nat44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
760                                   vlib_cli_command_t * cmd)
761 {
762   snat_main_t *sm = &snat_main;
763   snat_interface_t *i;
764   vnet_main_t *vnm = vnet_get_main ();
765
766   vlib_cli_output (vm, "NAT44 interfaces:");
767   pool_foreach (i, sm->interfaces)
768    {
769     vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
770                      i->sw_if_index,
771                      (nat_interface_is_inside(i) &&
772                       nat_interface_is_outside(i)) ? "in out" :
773                      (nat_interface_is_inside(i) ? "in" : "out"));
774   }
775
776   pool_foreach (i, sm->output_feature_interfaces)
777    {
778     vlib_cli_output (vm, " %U output-feature %s",
779                      format_vnet_sw_if_index_name, vnm,
780                      i->sw_if_index,
781                      (nat_interface_is_inside(i) &&
782                       nat_interface_is_outside(i)) ? "in out" :
783                      (nat_interface_is_inside(i) ? "in" : "out"));
784   }
785
786   return 0;
787 }
788
789 static clib_error_t *
790 add_static_mapping_command_fn (vlib_main_t * vm,
791                                unformat_input_t * input,
792                                vlib_cli_command_t * cmd)
793 {
794   unformat_input_t _line_input, *line_input = &_line_input;
795   clib_error_t *error = 0;
796   ip4_address_t l_addr, e_addr, exact_addr;
797   u32 l_port = 0, e_port = 0, vrf_id = ~0;
798   int is_add = 1, addr_only = 1, rv, exact = 0;
799   u32 sw_if_index = ~0;
800   vnet_main_t *vnm = vnet_get_main ();
801   nat_protocol_t proto = NAT_PROTOCOL_OTHER;
802   u8 proto_set = 0;
803   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
804   u8 out2in_only = 0;
805
806   /* Get a line of input. */
807   if (!unformat_user (input, unformat_line_input, line_input))
808     return 0;
809
810   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
811     {
812       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
813                     &l_port))
814         addr_only = 0;
815       else
816         if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
817         ;
818       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
819                          &e_addr, &e_port))
820         addr_only = 0;
821       else if (unformat (line_input, "external %U", unformat_ip4_address,
822                          &e_addr))
823         ;
824       else if (unformat (line_input, "external %U %u",
825                          unformat_vnet_sw_interface, vnm, &sw_if_index,
826                          &e_port))
827         addr_only = 0;
828       else if (unformat (line_input, "external %U",
829                          unformat_vnet_sw_interface, vnm, &sw_if_index))
830         ;
831       else if (unformat (line_input, "exact %U", unformat_ip4_address,
832                          &exact_addr))
833         exact = 1;
834       else if (unformat (line_input, "vrf %u", &vrf_id))
835         ;
836       else if (unformat (line_input, "%U", unformat_nat_protocol, &proto))
837         proto_set = 1;
838       else if (unformat (line_input, "twice-nat"))
839         twice_nat = TWICE_NAT;
840       else if (unformat (line_input, "self-twice-nat"))
841         twice_nat = TWICE_NAT_SELF;
842       else if (unformat (line_input, "out2in-only"))
843         out2in_only = 1;
844       else if (unformat (line_input, "del"))
845         is_add = 0;
846       else
847         {
848           error = clib_error_return (0, "unknown input: '%U'",
849                                      format_unformat_error, line_input);
850           goto done;
851         }
852     }
853
854   if (twice_nat && addr_only)
855     {
856       error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
857       goto done;
858     }
859
860   if (addr_only)
861     {
862       if (proto_set)
863         {
864           error =
865             clib_error_return (0,
866                                "address only mapping doesn't support protocol");
867           goto done;
868         }
869     }
870   else if (!proto_set)
871     {
872       error = clib_error_return (0, "protocol is required");
873       goto done;
874     }
875
876   rv = snat_add_static_mapping (
877     l_addr, e_addr, clib_host_to_net_u16 (l_port),
878     clib_host_to_net_u16 (e_port), vrf_id, addr_only, sw_if_index, proto,
879     is_add, twice_nat, out2in_only, 0, 0, exact_addr, exact);
880
881   switch (rv)
882     {
883     case VNET_API_ERROR_INVALID_VALUE:
884       error = clib_error_return (0, "External port already in use.");
885       goto done;
886     case VNET_API_ERROR_NO_SUCH_ENTRY:
887       if (is_add)
888         error = clib_error_return (0, "External address must be allocated.");
889       else
890         error = clib_error_return (0, "Mapping not exist.");
891       goto done;
892     case VNET_API_ERROR_NO_SUCH_FIB:
893       error = clib_error_return (0, "No such VRF id.");
894       goto done;
895     case VNET_API_ERROR_VALUE_EXIST:
896       error = clib_error_return (0, "Mapping already exist.");
897       goto done;
898     default:
899       break;
900     }
901
902 done:
903   unformat_free (line_input);
904
905   return error;
906 }
907
908 static clib_error_t *
909 add_identity_mapping_command_fn (vlib_main_t * vm,
910                                  unformat_input_t * input,
911                                  vlib_cli_command_t * cmd)
912 {
913   unformat_input_t _line_input, *line_input = &_line_input;
914   clib_error_t *error = 0;
915   ip4_address_t addr, pool_addr = { 0 };
916   u32 port = 0, vrf_id = ~0;
917   int is_add = 1;
918   int addr_only = 1;
919   u32 sw_if_index = ~0;
920   vnet_main_t *vnm = vnet_get_main ();
921   int rv;
922   nat_protocol_t proto;
923
924   addr.as_u32 = 0;
925
926   /* Get a line of input. */
927   if (!unformat_user (input, unformat_line_input, line_input))
928     return 0;
929
930   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
931     {
932       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
933         ;
934       else if (unformat (line_input, "external %U",
935                          unformat_vnet_sw_interface, vnm, &sw_if_index))
936         ;
937       else if (unformat (line_input, "vrf %u", &vrf_id))
938         ;
939       else if (unformat (line_input, "%U %u", unformat_nat_protocol, &proto,
940                          &port))
941         addr_only = 0;
942       else if (unformat (line_input, "del"))
943         is_add = 0;
944       else
945         {
946           error = clib_error_return (0, "unknown input: '%U'",
947                                      format_unformat_error, line_input);
948           goto done;
949         }
950     }
951
952   rv = snat_add_static_mapping (
953     addr, addr, clib_host_to_net_u16 (port), clib_host_to_net_u16 (port),
954     vrf_id, addr_only, sw_if_index, proto, is_add, 0, 0, 0, 1, pool_addr, 0);
955
956   switch (rv)
957     {
958     case VNET_API_ERROR_INVALID_VALUE:
959       error = clib_error_return (0, "External port already in use.");
960       goto done;
961     case VNET_API_ERROR_NO_SUCH_ENTRY:
962       if (is_add)
963         error = clib_error_return (0, "External address must be allocated.");
964       else
965         error = clib_error_return (0, "Mapping not exist.");
966       goto done;
967     case VNET_API_ERROR_NO_SUCH_FIB:
968       error = clib_error_return (0, "No such VRF id.");
969       goto done;
970     case VNET_API_ERROR_VALUE_EXIST:
971       error = clib_error_return (0, "Mapping already exist.");
972       goto done;
973     default:
974       break;
975     }
976
977 done:
978   unformat_free (line_input);
979
980   return error;
981 }
982
983 static clib_error_t *
984 add_lb_static_mapping_command_fn (vlib_main_t * vm,
985                                   unformat_input_t * input,
986                                   vlib_cli_command_t * cmd)
987 {
988   unformat_input_t _line_input, *line_input = &_line_input;
989   clib_error_t *error = 0;
990   ip4_address_t l_addr, e_addr;
991   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0, affinity = 0;
992   int is_add = 1;
993   int rv;
994   nat_protocol_t proto;
995   u8 proto_set = 0;
996   nat44_lb_addr_port_t *locals = 0, local;
997   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
998   u8 out2in_only = 0;
999
1000   /* Get a line of input. */
1001   if (!unformat_user (input, unformat_line_input, line_input))
1002     return 0;
1003
1004   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1005     {
1006       if (unformat (line_input, "local %U:%u probability %u",
1007                     unformat_ip4_address, &l_addr, &l_port, &probability))
1008         {
1009           clib_memset (&local, 0, sizeof (local));
1010           local.addr = l_addr;
1011           local.port = (u16) l_port;
1012           local.probability = (u8) probability;
1013           vec_add1 (locals, local);
1014         }
1015       else if (unformat (line_input, "local %U:%u vrf %u probability %u",
1016                          unformat_ip4_address, &l_addr, &l_port, &vrf_id,
1017                          &probability))
1018         {
1019           clib_memset (&local, 0, sizeof (local));
1020           local.addr = l_addr;
1021           local.port = (u16) l_port;
1022           local.probability = (u8) probability;
1023           local.vrf_id = vrf_id;
1024           vec_add1 (locals, local);
1025         }
1026       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1027                          &e_addr, &e_port))
1028         ;
1029       else if (unformat (line_input, "protocol %U", unformat_nat_protocol,
1030                          &proto))
1031         proto_set = 1;
1032       else if (unformat (line_input, "twice-nat"))
1033         twice_nat = TWICE_NAT;
1034       else if (unformat (line_input, "self-twice-nat"))
1035         twice_nat = TWICE_NAT_SELF;
1036       else if (unformat (line_input, "out2in-only"))
1037         out2in_only = 1;
1038       else if (unformat (line_input, "del"))
1039         is_add = 0;
1040       else if (unformat (line_input, "affinity %u", &affinity))
1041         ;
1042       else
1043         {
1044           error = clib_error_return (0, "unknown input: '%U'",
1045                                      format_unformat_error, line_input);
1046           goto done;
1047         }
1048     }
1049
1050   if (vec_len (locals) < 2)
1051     {
1052       error = clib_error_return (0, "at least two local must be set");
1053       goto done;
1054     }
1055
1056   if (!proto_set)
1057     {
1058       error = clib_error_return (0, "missing protocol");
1059       goto done;
1060     }
1061
1062   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, locals,
1063                                         is_add, twice_nat, out2in_only, 0,
1064                                         affinity);
1065
1066   switch (rv)
1067     {
1068     case VNET_API_ERROR_INVALID_VALUE:
1069       error = clib_error_return (0, "External port already in use.");
1070       goto done;
1071     case VNET_API_ERROR_NO_SUCH_ENTRY:
1072       if (is_add)
1073         error = clib_error_return (0, "External address must be allocated.");
1074       else
1075         error = clib_error_return (0, "Mapping not exist.");
1076       goto done;
1077     case VNET_API_ERROR_VALUE_EXIST:
1078       error = clib_error_return (0, "Mapping already exist.");
1079       goto done;
1080     default:
1081       break;
1082     }
1083
1084 done:
1085   unformat_free (line_input);
1086   vec_free (locals);
1087
1088   return error;
1089 }
1090
1091 static clib_error_t *
1092 add_lb_backend_command_fn (vlib_main_t * vm,
1093                            unformat_input_t * input, vlib_cli_command_t * cmd)
1094 {
1095   unformat_input_t _line_input, *line_input = &_line_input;
1096   clib_error_t *error = 0;
1097   ip4_address_t l_addr, e_addr;
1098   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
1099   int is_add = 1;
1100   int rv;
1101   nat_protocol_t proto;
1102   u8 proto_set = 0;
1103
1104   /* Get a line of input. */
1105   if (!unformat_user (input, unformat_line_input, line_input))
1106     return 0;
1107
1108   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1109     {
1110       if (unformat (line_input, "local %U:%u probability %u",
1111                     unformat_ip4_address, &l_addr, &l_port, &probability))
1112         ;
1113       else if (unformat (line_input, "local %U:%u vrf %u probability %u",
1114                          unformat_ip4_address, &l_addr, &l_port, &vrf_id,
1115                          &probability))
1116         ;
1117       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1118                          &e_addr, &e_port))
1119         ;
1120       else if (unformat (line_input, "protocol %U", unformat_nat_protocol,
1121                          &proto))
1122         proto_set = 1;
1123       else if (unformat (line_input, "del"))
1124         is_add = 0;
1125       else
1126         {
1127           error = clib_error_return (0, "unknown input: '%U'",
1128                                      format_unformat_error, line_input);
1129           goto done;
1130         }
1131     }
1132
1133   if (!l_port || !e_port)
1134     {
1135       error = clib_error_return (0, "local or external must be set");
1136       goto done;
1137     }
1138
1139   if (!proto_set)
1140     {
1141       error = clib_error_return (0, "missing protocol");
1142       goto done;
1143     }
1144
1145   rv =
1146     nat44_lb_static_mapping_add_del_local (e_addr, (u16) e_port, l_addr,
1147                                            l_port, proto, vrf_id, probability,
1148                                            is_add);
1149
1150   switch (rv)
1151     {
1152     case VNET_API_ERROR_INVALID_VALUE:
1153       error = clib_error_return (0, "External is not load-balancing static "
1154                                  "mapping.");
1155       goto done;
1156     case VNET_API_ERROR_NO_SUCH_ENTRY:
1157       error = clib_error_return (0, "Mapping or back-end not exist.");
1158       goto done;
1159     case VNET_API_ERROR_VALUE_EXIST:
1160       error = clib_error_return (0, "Back-end already exist.");
1161       goto done;
1162     case VNET_API_ERROR_UNSPECIFIED:
1163       error = clib_error_return (0, "At least two back-ends must remain");
1164       goto done;
1165     default:
1166       break;
1167     }
1168
1169 done:
1170   unformat_free (line_input);
1171
1172   return error;
1173 }
1174
1175 static clib_error_t *
1176 nat44_show_static_mappings_command_fn (vlib_main_t * vm,
1177                                        unformat_input_t * input,
1178                                        vlib_cli_command_t * cmd)
1179 {
1180   snat_main_t *sm = &snat_main;
1181   snat_static_mapping_t *m;
1182   snat_static_map_resolve_t *rp;
1183
1184   vlib_cli_output (vm, "NAT44 static mappings:");
1185   pool_foreach (m, sm->static_mappings)
1186    {
1187     vlib_cli_output (vm, " %U", format_snat_static_mapping, m);
1188   }
1189   vec_foreach (rp, sm->to_resolve)
1190     vlib_cli_output (vm, " %U", format_snat_static_map_to_resolve, rp);
1191
1192   return 0;
1193 }
1194
1195 static clib_error_t *
1196 snat_add_interface_address_command_fn (vlib_main_t * vm,
1197                                        unformat_input_t * input,
1198                                        vlib_cli_command_t * cmd)
1199 {
1200   snat_main_t *sm = &snat_main;
1201   unformat_input_t _line_input, *line_input = &_line_input;
1202   u32 sw_if_index;
1203   int rv;
1204   int is_del = 0;
1205   clib_error_t *error = 0;
1206   u8 twice_nat = 0;
1207
1208   /* Get a line of input. */
1209   if (!unformat_user (input, unformat_line_input, line_input))
1210     return 0;
1211
1212   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1213     {
1214       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
1215                     sm->vnet_main, &sw_if_index))
1216         ;
1217       else if (unformat (line_input, "twice-nat"))
1218         twice_nat = 1;
1219       else if (unformat (line_input, "del"))
1220         is_del = 1;
1221       else
1222         {
1223           error = clib_error_return (0, "unknown input '%U'",
1224                                      format_unformat_error, line_input);
1225           goto done;
1226         }
1227     }
1228
1229   rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
1230
1231   switch (rv)
1232     {
1233     case 0:
1234       break;
1235
1236     default:
1237       error = clib_error_return (0, "snat_add_interface_address returned %d",
1238                                  rv);
1239       goto done;
1240     }
1241
1242 done:
1243   unformat_free (line_input);
1244
1245   return error;
1246 }
1247
1248 static clib_error_t *
1249 nat44_show_interface_address_command_fn (vlib_main_t * vm,
1250                                          unformat_input_t * input,
1251                                          vlib_cli_command_t * cmd)
1252 {
1253   snat_main_t *sm = &snat_main;
1254   vnet_main_t *vnm = vnet_get_main ();
1255   u32 *sw_if_index;
1256
1257   vlib_cli_output (vm, "NAT44 pool address interfaces:");
1258   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
1259     {
1260       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
1261                        *sw_if_index);
1262     }
1263   vlib_cli_output (vm, "NAT44 twice-nat pool address interfaces:");
1264   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat)
1265     {
1266       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
1267                        *sw_if_index);
1268     }
1269
1270   return 0;
1271 }
1272
1273 static clib_error_t *
1274 nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
1275                                 vlib_cli_command_t * cmd)
1276 {
1277   unformat_input_t _line_input, *line_input = &_line_input;
1278   clib_error_t *error = 0;
1279   snat_main_per_thread_data_t *tsm;
1280   snat_main_t *sm = &snat_main;
1281
1282   int i = 0;
1283
1284   if (!unformat_user (input, unformat_line_input, line_input))
1285     goto print;
1286
1287   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1288     {
1289       error = clib_error_return (0, "unknown input '%U'",
1290                                  format_unformat_error, line_input);
1291       break;
1292     }
1293   unformat_free (line_input);
1294
1295 print:
1296     vlib_cli_output (vm, "NAT44 ED sessions:");
1297
1298   vec_foreach_index (i, sm->per_thread_data)
1299     {
1300       tsm = vec_elt_at_index (sm->per_thread_data, i);
1301
1302       vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n",
1303                        i, vlib_worker_threads[i].name,
1304                        pool_elts (tsm->sessions));
1305
1306           snat_session_t *s;
1307           pool_foreach (s, tsm->sessions)
1308            {
1309             vlib_cli_output (vm, "  %U\n", format_snat_session, tsm, s);
1310           }
1311     }
1312   return error;
1313 }
1314
1315 static clib_error_t *
1316 nat44_set_session_limit_command_fn (vlib_main_t * vm,
1317                                     unformat_input_t * input,
1318                                     vlib_cli_command_t * cmd)
1319 {
1320   unformat_input_t _line_input, *line_input = &_line_input;
1321   clib_error_t *error = 0;
1322
1323   u32 session_limit = 0, vrf_id = 0;
1324
1325   /* Get a line of input. */
1326   if (!unformat_user (input, unformat_line_input, line_input))
1327     return 0;
1328
1329   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1330     {
1331       if (unformat (line_input, "%u", &session_limit))
1332         ;
1333       else if (unformat (line_input, "vrf %u", &vrf_id))
1334         ;
1335       else
1336         {
1337           error = clib_error_return (0, "unknown input '%U'",
1338                                      format_unformat_error, line_input);
1339           goto done;
1340         }
1341     }
1342
1343   if (!session_limit)
1344     error = clib_error_return (0, "missing value of session limit");
1345   else if (nat44_update_session_limit (session_limit, vrf_id))
1346     error = clib_error_return (0, "nat44_set_session_limit failed");
1347
1348 done:
1349   unformat_free (line_input);
1350
1351   return error;
1352 }
1353
1354 static clib_error_t *
1355 nat44_del_session_command_fn (vlib_main_t * vm,
1356                               unformat_input_t * input,
1357                               vlib_cli_command_t * cmd)
1358 {
1359   snat_main_t *sm = &snat_main;
1360   unformat_input_t _line_input, *line_input = &_line_input;
1361   u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
1362   clib_error_t *error = 0;
1363   ip4_address_t addr, eh_addr;
1364   nat_protocol_t proto;
1365   int is_in = 0;
1366   int rv;
1367
1368   /* Get a line of input. */
1369   if (!unformat_user (input, unformat_line_input, line_input))
1370     return 0;
1371
1372   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1373     {
1374       if (unformat
1375           (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
1376            unformat_nat_protocol, &proto))
1377         ;
1378       else if (unformat (line_input, "in"))
1379         {
1380           is_in = 1;
1381           vrf_id = sm->inside_vrf_id;
1382         }
1383       else if (unformat (line_input, "out"))
1384         {
1385           is_in = 0;
1386           vrf_id = sm->outside_vrf_id;
1387         }
1388       else if (unformat (line_input, "vrf %u", &vrf_id))
1389         ;
1390       else if (unformat (line_input, "external-host %U:%u",
1391                          unformat_ip4_address, &eh_addr, &eh_port))
1392         ;
1393       else
1394         {
1395           error = clib_error_return (0, "unknown input '%U'",
1396                                      format_unformat_error, line_input);
1397           goto done;
1398         }
1399     }
1400
1401     rv =
1402       nat44_del_ed_session (sm, &addr, clib_host_to_net_u16 (port), &eh_addr,
1403                             clib_host_to_net_u16 (eh_port),
1404                             nat_proto_to_ip_proto (proto), vrf_id, is_in);
1405
1406   switch (rv)
1407     {
1408     case 0:
1409       break;
1410
1411     default:
1412       error = clib_error_return (0, "nat44_del_session returned %d", rv);
1413       goto done;
1414     }
1415
1416 done:
1417   unformat_free (line_input);
1418
1419   return error;
1420 }
1421
1422 static clib_error_t *
1423 snat_forwarding_set_command_fn (vlib_main_t * vm,
1424                                 unformat_input_t * input,
1425                                 vlib_cli_command_t * cmd)
1426 {
1427   snat_main_t *sm = &snat_main;
1428   unformat_input_t _line_input, *line_input = &_line_input;
1429   u8 forwarding_enable;
1430   u8 forwarding_enable_set = 0;
1431   clib_error_t *error = 0;
1432
1433   /* Get a line of input. */
1434   if (!unformat_user (input, unformat_line_input, line_input))
1435     return clib_error_return (0, "'enable' or 'disable' expected");
1436
1437   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1438     {
1439       if (!forwarding_enable_set && unformat (line_input, "enable"))
1440         {
1441           forwarding_enable = 1;
1442           forwarding_enable_set = 1;
1443         }
1444       else if (!forwarding_enable_set && unformat (line_input, "disable"))
1445         {
1446           forwarding_enable = 0;
1447           forwarding_enable_set = 1;
1448         }
1449       else
1450         {
1451           error = clib_error_return (0, "unknown input '%U'",
1452                                      format_unformat_error, line_input);
1453           goto done;
1454         }
1455     }
1456
1457   if (!forwarding_enable_set)
1458     {
1459       error = clib_error_return (0, "'enable' or 'disable' expected");
1460       goto done;
1461     }
1462
1463   sm->forwarding_enabled = forwarding_enable;
1464
1465 done:
1466   unformat_free (line_input);
1467
1468   return error;
1469 }
1470
1471 static clib_error_t *
1472 set_timeout_command_fn (vlib_main_t * vm,
1473                         unformat_input_t * input, vlib_cli_command_t * cmd)
1474 {
1475   snat_main_t *sm = &snat_main;
1476   unformat_input_t _line_input, *line_input = &_line_input;
1477   clib_error_t *error = 0;
1478
1479   /* Get a line of input. */
1480   if (!unformat_user (input, unformat_line_input, line_input))
1481     return 0;
1482
1483   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1484     {
1485       if (unformat (line_input, "udp %u", &sm->timeouts.udp));
1486       else if (unformat (line_input, "tcp-established %u",
1487                          &sm->timeouts.tcp.established));
1488       else if (unformat (line_input, "tcp-transitory %u",
1489                          &sm->timeouts.tcp.transitory));
1490       else if (unformat (line_input, "icmp %u", &sm->timeouts.icmp));
1491       else if (unformat (line_input, "reset"))
1492         nat_reset_timeouts (&sm->timeouts);
1493       else
1494         {
1495           error = clib_error_return (0, "unknown input '%U'",
1496                                      format_unformat_error, line_input);
1497           goto done;
1498         }
1499     }
1500 done:
1501   unformat_free (line_input);
1502   return error;
1503 }
1504
1505 static clib_error_t *
1506 nat_show_timeouts_command_fn (vlib_main_t * vm,
1507                               unformat_input_t * input,
1508                               vlib_cli_command_t * cmd)
1509 {
1510   snat_main_t *sm = &snat_main;
1511
1512   vlib_cli_output (vm, "udp timeout: %dsec", sm->timeouts.udp);
1513   vlib_cli_output (vm, "tcp-established timeout: %dsec",
1514                    sm->timeouts.tcp.established);
1515   vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
1516                    sm->timeouts.tcp.transitory);
1517   vlib_cli_output (vm, "icmp timeout: %dsec", sm->timeouts.icmp);
1518
1519   return 0;
1520 }
1521
1522 static clib_error_t *
1523 set_frame_queue_nelts_command_fn (vlib_main_t *vm, unformat_input_t *input,
1524                                   vlib_cli_command_t *cmd)
1525 {
1526   unformat_input_t _line_input, *line_input = &_line_input;
1527   clib_error_t *error = 0;
1528   u32 frame_queue_nelts = 0;
1529   /* Get a line of input. */
1530   if (!unformat_user (input, unformat_line_input, line_input))
1531     return 0;
1532   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1533     {
1534       if (unformat (line_input, "%u", &frame_queue_nelts))
1535         ;
1536       else
1537         {
1538           error = clib_error_return (0, "unknown input '%U'",
1539                                      format_unformat_error, line_input);
1540           goto done;
1541         }
1542     }
1543   if (!frame_queue_nelts)
1544     {
1545       error = clib_error_return (0, "frame_queue_nelts cannot be zero");
1546       goto done;
1547     }
1548   if (snat_set_frame_queue_nelts (frame_queue_nelts) != 0)
1549     {
1550       error = clib_error_return (0, "snat_set_frame_queue_nelts failed");
1551       goto done;
1552     }
1553 done:
1554   unformat_free (line_input);
1555   return error;
1556 }
1557
1558 /*?
1559  * @cliexpar
1560  * @cliexstart{nat44 enable}
1561  * Enable nat44 plugin
1562  * To enable nat44, use:
1563  *  vpp# nat44 enable sessions <n>
1564  * To enable nat44 static mapping only, use:
1565  *  vpp# nat44 enable sessions <n> static-mapping
1566  * To enable nat44 static mapping with connection tracking, use:
1567  *  vpp# nat44 enable sessions <n> static-mapping connection-tracking
1568  * To set inside-vrf outside-vrf, use:
1569  *  vpp# nat44 enable sessions <n> inside-vrf <id> outside-vrf <id>
1570  * @cliexend
1571 ?*/
1572 VLIB_CLI_COMMAND (nat44_enable_command, static) = {
1573   .path = "nat44 enable",
1574   .short_help =
1575     "nat44 enable sessions <max-number> [static-mappig-only "
1576     "[connection-tracking]] [inside-vrf <vrf-id>] [outside-vrf <vrf-id>]",
1577   .function = nat44_enable_command_fn,
1578 };
1579
1580 /*?
1581  * @cliexpar
1582  * @cliexstart{nat44 disable}
1583  * Disable nat44 plugin
1584  * To disable nat44, use:
1585  *  vpp# nat44 disable
1586  * @cliexend
1587 ?*/
1588 VLIB_CLI_COMMAND (nat44_disable_command, static) = {
1589   .path = "nat44 disable",
1590   .short_help = "nat44 disable",
1591   .function = nat44_disable_command_fn,
1592 };
1593
1594 /*?
1595  * @cliexpar
1596  * @cliexstart{set snat workers}
1597  * Set NAT workers if 2 or more workers available, use:
1598  *  vpp# set snat workers 0-2,5
1599  * @cliexend
1600 ?*/
1601 VLIB_CLI_COMMAND (set_workers_command, static) = {
1602   .path = "set nat workers",
1603   .function = set_workers_command_fn,
1604   .short_help = "set nat workers <workers-list>",
1605 };
1606
1607 /*?
1608  * @cliexpar
1609  * @cliexstart{show nat workers}
1610  * Show NAT workers.
1611  *  vpp# show nat workers:
1612  *  2 workers
1613  *    vpp_wk_0
1614  *    vpp_wk_1
1615  * @cliexend
1616 ?*/
1617 VLIB_CLI_COMMAND (nat_show_workers_command, static) = {
1618   .path = "show nat workers",
1619   .short_help = "show nat workers",
1620   .function = nat_show_workers_commnad_fn,
1621 };
1622
1623 /*?
1624  * @cliexpar
1625  * @cliexstart{set nat timeout}
1626  * Set values of timeouts for NAT sessions (in seconds), use:
1627  *  vpp# set nat timeout udp 120 tcp-established 7500 tcp-transitory 250 icmp 90
1628  * To reset default values use:
1629  *  vpp# set nat timeout reset
1630  * @cliexend
1631 ?*/
1632 VLIB_CLI_COMMAND (set_timeout_command, static) = {
1633   .path = "set nat timeout",
1634   .function = set_timeout_command_fn,
1635   .short_help =
1636     "set nat timeout [udp <sec> | tcp-established <sec> "
1637     "tcp-transitory <sec> | icmp <sec> | reset]",
1638 };
1639
1640 /*?
1641  * @cliexpar
1642  * @cliexstart{show nat timeouts}
1643  * Show values of timeouts for NAT sessions.
1644  * vpp# show nat timeouts
1645  * udp timeout: 300sec
1646  * tcp-established timeout: 7440sec
1647  * tcp-transitory timeout: 240sec
1648  * icmp timeout: 60sec
1649  * @cliexend
1650 ?*/
1651 VLIB_CLI_COMMAND (nat_show_timeouts_command, static) = {
1652   .path = "show nat timeouts",
1653   .short_help = "show nat timeouts",
1654   .function = nat_show_timeouts_command_fn,
1655 };
1656
1657 /*?
1658  * @cliexpar
1659  * @cliexstart{set nat frame-queue-nelts}
1660  * Set number of worker handoff frame queue elements.
1661  * @cliexend
1662 ?*/
1663 VLIB_CLI_COMMAND (set_frame_queue_nelts_command, static) = {
1664   .path = "set nat frame-queue-nelts",
1665   .function = set_frame_queue_nelts_command_fn,
1666   .short_help = "set nat frame-queue-nelts <number>",
1667 };
1668
1669 /*?
1670  * @cliexpar
1671  * @cliexstart{nat set logging level}
1672  * To set NAT logging level use:
1673  * Set nat logging level
1674  * @cliexend
1675 ?*/
1676 VLIB_CLI_COMMAND (snat_set_log_level_command, static) = {
1677   .path = "nat set logging level",
1678   .function = snat_set_log_level_command_fn,
1679   .short_help = "nat set logging level <level>",
1680 };
1681
1682 /*?
1683  * @cliexpar
1684  * @cliexstart{snat ipfix logging}
1685  * To enable NAT IPFIX logging use:
1686  *  vpp# nat ipfix logging
1687  * To set IPFIX exporter use:
1688  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
1689  * @cliexend
1690 ?*/
1691 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
1692   .path = "nat ipfix logging",
1693   .function = snat_ipfix_logging_enable_disable_command_fn,
1694   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
1695 };
1696
1697 /*?
1698  * @cliexpar
1699  * @cliexstart{nat mss-clamping}
1700  * Set TCP MSS rewriting configuration
1701  * To enable TCP MSS rewriting use:
1702  *  vpp# nat mss-clamping 1452
1703  * To disbale TCP MSS rewriting use:
1704  *  vpp# nat mss-clamping disable
1705  * @cliexend
1706 ?*/
1707 VLIB_CLI_COMMAND (nat_set_mss_clamping_command, static) = {
1708     .path = "nat mss-clamping",
1709     .short_help = "nat mss-clamping <mss-value>|disable",
1710     .function = nat_set_mss_clamping_command_fn,
1711 };
1712
1713 /*?
1714  * @cliexpar
1715  * @cliexstart{show nat mss-clamping}
1716  * Show TCP MSS rewriting configuration
1717  * @cliexend
1718 ?*/
1719 VLIB_CLI_COMMAND (nat_show_mss_clamping_command, static) = {
1720     .path = "show nat mss-clamping",
1721     .short_help = "show nat mss-clamping",
1722     .function = nat_show_mss_clamping_command_fn,
1723 };
1724
1725 /*?
1726  * @cliexpar
1727  * @cliexstart{show nat44 hash tables}
1728  * Show NAT44 hash tables
1729  * @cliexend
1730 ?*/
1731 VLIB_CLI_COMMAND (nat44_show_hash, static) = {
1732   .path = "show nat44 hash tables",
1733   .short_help = "show nat44 hash tables [detail|verbose]",
1734   .function = nat44_show_hash_command_fn,
1735 };
1736
1737 /*?
1738  * @cliexpar
1739  * @cliexstart{nat44 add address}
1740  * Add/delete NAT44 pool address.
1741  * To add NAT44 pool address use:
1742  *  vpp# nat44 add address 172.16.1.3
1743  *  vpp# nat44 add address 172.16.2.2 - 172.16.2.24
1744  * To add NAT44 pool address for specific tenant (identified by VRF id) use:
1745  *  vpp# nat44 add address 172.16.1.3 tenant-vrf 10
1746  * @cliexend
1747 ?*/
1748 VLIB_CLI_COMMAND (add_address_command, static) = {
1749   .path = "nat44 add address",
1750   .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1751                 "[tenant-vrf <vrf-id>] [twice-nat] [del]",
1752   .function = add_address_command_fn,
1753 };
1754
1755 /*?
1756  * @cliexpar
1757  * @cliexstart{show nat44 summary}
1758  * Show NAT44 summary
1759  * vpp# show nat44 summary
1760  * @cliexend
1761 ?*/
1762 VLIB_CLI_COMMAND (nat44_show_summary_command, static) = {
1763   .path = "show nat44 summary",
1764   .short_help = "show nat44 summary",
1765   .function = nat44_show_summary_command_fn,
1766 };
1767
1768 /*?
1769  * @cliexpar
1770  * @cliexstart{show nat44 addresses}
1771  * Show NAT44 pool addresses.
1772  * vpp# show nat44 addresses
1773  * NAT44 pool addresses:
1774  * 172.16.2.2
1775  *   tenant VRF independent
1776  *   10 busy udp ports
1777  *   0 busy tcp ports
1778  *   0 busy icmp ports
1779  * 172.16.1.3
1780  *   tenant VRF: 10
1781  *   0 busy udp ports
1782  *   2 busy tcp ports
1783  *   0 busy icmp ports
1784  * NAT44 twice-nat pool addresses:
1785  * 10.20.30.72
1786  *   tenant VRF independent
1787  *   0 busy udp ports
1788  *   0 busy tcp ports
1789  *   0 busy icmp ports
1790  * @cliexend
1791 ?*/
1792 VLIB_CLI_COMMAND (nat44_show_addresses_command, static) = {
1793   .path = "show nat44 addresses",
1794   .short_help = "show nat44 addresses",
1795   .function = nat44_show_addresses_command_fn,
1796 };
1797
1798 /*?
1799  * @cliexpar
1800  * @cliexstart{set interface nat44}
1801  * Enable/disable NAT44 feature on the interface.
1802  * To enable NAT44 feature with local network interface use:
1803  *  vpp# set interface nat44 in GigabitEthernet0/8/0
1804  * To enable NAT44 feature with external network interface use:
1805  *  vpp# set interface nat44 out GigabitEthernet0/a/0
1806  * @cliexend
1807 ?*/
1808 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1809   .path = "set interface nat44",
1810   .function = snat_feature_command_fn,
1811   .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1812                 "[del]",
1813 };
1814
1815 /*?
1816  * @cliexpar
1817  * @cliexstart{show nat44 interfaces}
1818  * Show interfaces with NAT44 feature.
1819  * vpp# show nat44 interfaces
1820  * NAT44 interfaces:
1821  *  GigabitEthernet0/8/0 in
1822  *  GigabitEthernet0/a/0 out
1823  * @cliexend
1824 ?*/
1825 VLIB_CLI_COMMAND (nat44_show_interfaces_command, static) = {
1826   .path = "show nat44 interfaces",
1827   .short_help = "show nat44 interfaces",
1828   .function = nat44_show_interfaces_command_fn,
1829 };
1830
1831 /*?
1832  * @cliexpar
1833  * @cliexstart{nat44 add static mapping}
1834  * Static mapping allows hosts on the external network to initiate connection
1835  * to to the local network host.
1836  * To create static mapping between local host address 10.0.0.3 port 6303 and
1837  * external address 4.4.4.4 port 3606 for TCP protocol use:
1838  *  vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
1839  * If not runnig "static mapping only" NAT plugin mode use before:
1840  *  vpp# nat44 add address 4.4.4.4
1841  * To create address only static mapping between local and external address use:
1842  *  vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
1843  * To create ICMP static mapping between local and external with ICMP echo
1844  * identifier 10 use:
1845  *  vpp# nat44 add static mapping icmp local 10.0.0.3 10 external 4.4.4.4 10
1846  * To force use of specific pool address, vrf independent
1847  *  vpp# nat44 add static mapping local 10.0.0.2 1234 external 10.0.2.2 1234 twice-nat exact 10.0.1.2
1848  * @cliexend
1849 ?*/
1850 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1851   .path = "nat44 add static mapping",
1852   .function = add_static_mapping_command_fn,
1853   .short_help =
1854     "nat44 add static mapping tcp|udp|icmp local <addr> [<port|icmp-echo-id>] "
1855     "external <addr> [<port|icmp-echo-id>] [vrf <table-id>] [twice-nat|self-twice-nat] "
1856     "[out2in-only] [exact <pool-addr>] [del]",
1857 };
1858
1859 /*?
1860  * @cliexpar
1861  * @cliexstart{nat44 add identity mapping}
1862  * Identity mapping translate an IP address to itself.
1863  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
1864  * use:
1865  *  vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
1866  * To create identity mapping for address 10.0.0.3 use:
1867  *  vpp# nat44 add identity mapping 10.0.0.3
1868  * To create identity mapping for DHCP addressed interface use:
1869  *  vpp# nat44 add identity mapping external GigabitEthernet0/a/0 tcp 3606
1870  * @cliexend
1871 ?*/
1872 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
1873   .path = "nat44 add identity mapping",
1874   .function = add_identity_mapping_command_fn,
1875   .short_help = "nat44 add identity mapping <ip4-addr>|external <interface> "
1876     "[<protocol> <port>] [vrf <table-id>] [del]",
1877 };
1878
1879 /*?
1880  * @cliexpar
1881  * @cliexstart{nat44 add load-balancing static mapping}
1882  * Service load balancing using NAT44
1883  * To add static mapping with load balancing for service with external IP
1884  * address 1.2.3.4 and TCP port 80 and mapped to 2 local servers
1885  * 10.100.10.10:8080 and 10.100.10.20:8080 with probability 80% resp. 20% use:
1886  *  vpp# nat44 add load-balancing static mapping protocol tcp external 1.2.3.4:80 local 10.100.10.10:8080 probability 80 local 10.100.10.20:8080 probability 20
1887  * @cliexend
1888 ?*/
1889 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
1890   .path = "nat44 add load-balancing static mapping",
1891   .function = add_lb_static_mapping_command_fn,
1892   .short_help =
1893     "nat44 add load-balancing static mapping protocol tcp|udp "
1894     "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
1895     "probability <n> [twice-nat|self-twice-nat] [out2in-only] "
1896     "[affinity <timeout-seconds>] [del]",
1897 };
1898
1899 /*?
1900  * @cliexpar
1901  * @cliexstart{nat44 add load-balancing static mapping}
1902  * Modify service load balancing using NAT44
1903  * To add new back-end server 10.100.10.30:8080 for service load balancing
1904  * static mapping with external IP address 1.2.3.4 and TCP port 80 use:
1905  *  vpp# nat44 add load-balancing back-end protocol tcp external 1.2.3.4:80 local 10.100.10.30:8080 probability 25
1906  * @cliexend
1907 ?*/
1908 VLIB_CLI_COMMAND (add_lb_backend_command, static) = {
1909   .path = "nat44 add load-balancing back-end",
1910   .function = add_lb_backend_command_fn,
1911   .short_help =
1912     "nat44 add load-balancing back-end protocol tcp|udp "
1913     "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
1914     "probability <n> [del]",
1915 };
1916
1917 /*?
1918  * @cliexpar
1919  * @cliexstart{show nat44 static mappings}
1920  * Show NAT44 static mappings.
1921  * vpp# show nat44 static mappings
1922  * NAT44 static mappings:
1923  *  local 10.0.0.3 external 4.4.4.4 vrf 0
1924  *  tcp local 192.168.0.4:6303 external 4.4.4.3:3606 vrf 0
1925  *  tcp vrf 0 external 1.2.3.4:80  out2in-only
1926  *   local 10.100.10.10:8080 probability 80
1927  *   local 10.100.10.20:8080 probability 20
1928  *  tcp local 10.100.3.8:8080 external 169.10.10.1:80 vrf 0 twice-nat
1929  *  tcp local 10.0.0.10:3603 external GigabitEthernet0/a/0:6306 vrf 10
1930  * @cliexend
1931 ?*/
1932 VLIB_CLI_COMMAND (nat44_show_static_mappings_command, static) = {
1933   .path = "show nat44 static mappings",
1934   .short_help = "show nat44 static mappings",
1935   .function = nat44_show_static_mappings_command_fn,
1936 };
1937
1938 /*?
1939  * @cliexpar
1940  * @cliexstart{nat44 add interface address}
1941  * Use NAT44 pool address from specific interfce
1942  * To add NAT44 pool address from specific interface use:
1943  *  vpp# nat44 add interface address GigabitEthernet0/8/0
1944  * @cliexend
1945 ?*/
1946 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
1947     .path = "nat44 add interface address",
1948     .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
1949     .function = snat_add_interface_address_command_fn,
1950 };
1951
1952 /*?
1953  * @cliexpar
1954  * @cliexstart{show nat44 interface address}
1955  * Show NAT44 pool address interfaces
1956  * vpp# show nat44 interface address
1957  * NAT44 pool address interfaces:
1958  *  GigabitEthernet0/a/0
1959  * NAT44 twice-nat pool address interfaces:
1960  *  GigabitEthernet0/8/0
1961  * @cliexend
1962 ?*/
1963 VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = {
1964   .path = "show nat44 interface address",
1965   .short_help = "show nat44 interface address",
1966   .function = nat44_show_interface_address_command_fn,
1967 };
1968
1969 /*?
1970  * @cliexpar
1971  * @cliexstart{show nat44 sessions}
1972  * Show NAT44 sessions.
1973  * @cliexend
1974 ?*/
1975 VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
1976   .path = "show nat44 sessions",
1977   .short_help = "show nat44 sessions",
1978   .function = nat44_show_sessions_command_fn,
1979 };
1980
1981 /*?
1982  * @cliexpar
1983  * @cliexstart{set nat44 session limit}
1984  * Set NAT44 session limit.
1985  * @cliexend
1986 ?*/
1987 VLIB_CLI_COMMAND (nat44_set_session_limit_command, static) = {
1988   .path = "set nat44 session limit",
1989   .short_help = "set nat44 session limit <limit> [vrf <table-id>]",
1990   .function = nat44_set_session_limit_command_fn,
1991 };
1992
1993 /*?
1994  * @cliexpar
1995  * @cliexstart{nat44 del session}
1996  * To administratively delete NAT44 session by inside address and port use:
1997  *  vpp# nat44 del session in 10.0.0.3:6303 tcp
1998  * To administratively delete NAT44 session by outside address and port use:
1999  *  vpp# nat44 del session out 1.0.0.3:6033 udp
2000  * @cliexend
2001 ?*/
2002 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
2003     .path = "nat44 del session",
2004     .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>] [external-host <addr>:<port>]",
2005     .function = nat44_del_session_command_fn,
2006 };
2007
2008 /*?
2009  * @cliexpar
2010  * @cliexstart{nat44 forwarding}
2011  * Enable or disable forwarding
2012  * Forward packets which don't match existing translation
2013  * or static mapping instead of dropping them.
2014  * To enable forwarding, use:
2015  *  vpp# nat44 forwarding enable
2016  * To disable forwarding, use:
2017  *  vpp# nat44 forwarding disable
2018  * @cliexend
2019 ?*/
2020 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
2021   .path = "nat44 forwarding",
2022   .short_help = "nat44 forwarding enable|disable",
2023   .function = snat_forwarding_set_command_fn,
2024 };
2025
2026 /*
2027  * fd.io coding-style-patch-verification: ON
2028  *
2029  * Local Variables:
2030  * eval: (c-set-style "gnu")
2031  * End:
2032  */