virtio: enable the interrupt support for uio_pci_generic
[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 #define _(n, d)                                                          \
452   oldest_index =                                                         \
453       clib_dlist_remove_head (tsm->lru_pool, tsm->n##_lru_head_index);   \
454   if (~0 != oldest_index)                                                \
455     {                                                                    \
456       oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);      \
457       s = pool_elt_at_index (tsm->sessions, oldest_elt->value);          \
458       sess_timeout_time =                                                \
459           s->last_heard + (f64)nat44_session_get_timeout (sm, s);        \
460       vlib_cli_output (vm, d " LRU min session timeout %llu (now %llu)", \
461                        sess_timeout_time, now);                          \
462       clib_dlist_addhead (tsm->lru_pool, tsm->n##_lru_head_index,        \
463                           oldest_index);                                 \
464     }
465   _(tcp_estab, "established tcp");
466   _(tcp_trans, "transitory tcp");
467   _(udp, "udp");
468   _(unk_proto, "unknown protocol");
469   _(icmp, "icmp");
470 #undef _
471 }
472
473 static clib_error_t *
474 nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
475                                vlib_cli_command_t * cmd)
476 {
477   snat_main_per_thread_data_t *tsm;
478   snat_main_t *sm = &snat_main;
479   snat_session_t *s;
480
481   u32 count = 0;
482
483   u64 now = vlib_time_now (vm);
484   u64 sess_timeout_time = 0;
485
486   u32 udp_sessions = 0;
487   u32 tcp_sessions = 0;
488   u32 icmp_sessions = 0;
489
490   u32 timed_out = 0;
491   u32 transitory = 0;
492   u32 transitory_wait_closed = 0;
493   u32 transitory_closed = 0;
494   u32 established = 0;
495
496   u32 fib;
497
498   for (fib = 0; fib < vec_len (sm->max_translations_per_fib); fib++)
499     vlib_cli_output (vm, "max translations per thread: %u fib %u",
500                      sm->max_translations_per_fib[fib], fib);
501
502   if (sm->num_workers > 1)
503     {
504       vec_foreach (tsm, sm->per_thread_data)
505         {
506           pool_foreach (s, tsm->sessions)
507            {
508             sess_timeout_time = s->last_heard +
509               (f64) nat44_session_get_timeout (sm, s);
510             if (now >= sess_timeout_time)
511               timed_out++;
512
513             switch (s->nat_proto)
514               {
515               case NAT_PROTOCOL_ICMP:
516                 icmp_sessions++;
517                 break;
518               case NAT_PROTOCOL_TCP:
519                 tcp_sessions++;
520                 if (s->state)
521                   {
522                     if (s->tcp_closed_timestamp)
523                       {
524                         if (now >= s->tcp_closed_timestamp)
525                           {
526                             ++transitory_closed;
527                           }
528                         else
529                           {
530                             ++transitory_wait_closed;
531                           }
532                       }
533                     transitory++;
534                   }
535                 else
536                   established++;
537                 break;
538               case NAT_PROTOCOL_UDP:
539               default:
540                 udp_sessions++;
541                 break;
542               }
543           }
544           nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
545           count += pool_elts (tsm->sessions);
546         }
547     }
548   else
549     {
550       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
551       pool_foreach (s, tsm->sessions)
552        {
553         sess_timeout_time = s->last_heard +
554             (f64) nat44_session_get_timeout (sm, s);
555         if (now >= sess_timeout_time)
556           timed_out++;
557
558         switch (s->nat_proto)
559           {
560           case NAT_PROTOCOL_ICMP:
561             icmp_sessions++;
562             break;
563           case NAT_PROTOCOL_TCP:
564             tcp_sessions++;
565             if (s->state)
566               {
567                 if (s->tcp_closed_timestamp)
568                   {
569                     if (now >= s->tcp_closed_timestamp)
570                       {
571                         ++transitory_closed;
572                       }
573                     else
574                       {
575                         ++transitory_wait_closed;
576                       }
577                   }
578                 transitory++;
579               }
580             else
581               established++;
582             break;
583           case NAT_PROTOCOL_UDP:
584           default:
585             udp_sessions++;
586             break;
587           }
588       }
589       nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
590       count = pool_elts (tsm->sessions);
591     }
592
593   vlib_cli_output (vm, "total timed out sessions: %u", timed_out);
594   vlib_cli_output (vm, "total sessions: %u", count);
595   vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions);
596   vlib_cli_output (vm, "total tcp established sessions: %u", established);
597   vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory);
598   vlib_cli_output (vm, "total tcp transitory (WAIT-CLOSED) sessions: %u",
599                    transitory_wait_closed);
600   vlib_cli_output (vm, "total tcp transitory (CLOSED) sessions: %u",
601                    transitory_closed);
602   vlib_cli_output (vm, "total udp sessions: %u", udp_sessions);
603   vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions);
604   return 0;
605 }
606
607 static clib_error_t *
608 nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
609                                  vlib_cli_command_t * cmd)
610 {
611   snat_main_t *sm = &snat_main;
612   snat_address_t *ap;
613
614   vlib_cli_output (vm, "NAT44 pool addresses:");
615   vec_foreach (ap, sm->addresses)
616     {
617       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
618       if (ap->fib_index != ~0)
619           vlib_cli_output (vm, "  tenant VRF: %u",
620             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
621       else
622         vlib_cli_output (vm, "  tenant VRF independent");
623     #define _(N, i, n, s) \
624       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
625       foreach_nat_protocol
626     #undef _
627     }
628   vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
629   vec_foreach (ap, sm->twice_nat_addresses)
630     {
631       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
632       if (ap->fib_index != ~0)
633           vlib_cli_output (vm, "  tenant VRF: %u",
634             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
635       else
636         vlib_cli_output (vm, "  tenant VRF independent");
637     #define _(N, i, n, s) \
638       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
639       foreach_nat_protocol
640     #undef _
641     }
642   return 0;
643 }
644
645 static clib_error_t *
646 snat_feature_command_fn (vlib_main_t * vm,
647                          unformat_input_t * input, vlib_cli_command_t * cmd)
648 {
649   unformat_input_t _line_input, *line_input = &_line_input;
650   vnet_main_t *vnm = vnet_get_main ();
651   clib_error_t *error = 0;
652   u32 sw_if_index;
653   u32 *inside_sw_if_indices = 0;
654   u32 *outside_sw_if_indices = 0;
655   u8 is_output_feature = 0;
656   int is_del = 0;
657   int i;
658
659   sw_if_index = ~0;
660
661   /* Get a line of input. */
662   if (!unformat_user (input, unformat_line_input, line_input))
663     return 0;
664
665   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
666     {
667       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
668                     vnm, &sw_if_index))
669         vec_add1 (inside_sw_if_indices, sw_if_index);
670       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
671                          vnm, &sw_if_index))
672         vec_add1 (outside_sw_if_indices, sw_if_index);
673       else if (unformat (line_input, "output-feature"))
674         is_output_feature = 1;
675       else if (unformat (line_input, "del"))
676         is_del = 1;
677       else
678         {
679           error = clib_error_return (0, "unknown input '%U'",
680                                      format_unformat_error, line_input);
681           goto done;
682         }
683     }
684
685   if (vec_len (inside_sw_if_indices))
686     {
687       for (i = 0; i < vec_len (inside_sw_if_indices); i++)
688         {
689           sw_if_index = inside_sw_if_indices[i];
690           if (is_output_feature)
691             {
692               if (snat_interface_add_del_output_feature
693                   (sw_if_index, 1, is_del))
694                 {
695                   error = clib_error_return (0, "%s %U failed",
696                                              is_del ? "del" : "add",
697                                              format_vnet_sw_if_index_name,
698                                              vnm, sw_if_index);
699                   goto done;
700                 }
701             }
702           else
703             {
704               if (snat_interface_add_del (sw_if_index, 1, is_del))
705                 {
706                   error = clib_error_return (0, "%s %U failed",
707                                              is_del ? "del" : "add",
708                                              format_vnet_sw_if_index_name,
709                                              vnm, sw_if_index);
710                   goto done;
711                 }
712             }
713         }
714     }
715
716   if (vec_len (outside_sw_if_indices))
717     {
718       for (i = 0; i < vec_len (outside_sw_if_indices); i++)
719         {
720           sw_if_index = outside_sw_if_indices[i];
721           if (is_output_feature)
722             {
723               if (snat_interface_add_del_output_feature
724                   (sw_if_index, 0, is_del))
725                 {
726                   error = clib_error_return (0, "%s %U failed",
727                                              is_del ? "del" : "add",
728                                              format_vnet_sw_if_index_name,
729                                              vnm, sw_if_index);
730                   goto done;
731                 }
732             }
733           else
734             {
735               if (snat_interface_add_del (sw_if_index, 0, is_del))
736                 {
737                   error = clib_error_return (0, "%s %U failed",
738                                              is_del ? "del" : "add",
739                                              format_vnet_sw_if_index_name,
740                                              vnm, sw_if_index);
741                   goto done;
742                 }
743             }
744         }
745     }
746
747 done:
748   unformat_free (line_input);
749   vec_free (inside_sw_if_indices);
750   vec_free (outside_sw_if_indices);
751
752   return error;
753 }
754
755 static clib_error_t *
756 nat44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
757                                   vlib_cli_command_t * cmd)
758 {
759   snat_main_t *sm = &snat_main;
760   snat_interface_t *i;
761   vnet_main_t *vnm = vnet_get_main ();
762
763   vlib_cli_output (vm, "NAT44 interfaces:");
764   pool_foreach (i, sm->interfaces)
765    {
766     vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
767                      i->sw_if_index,
768                      (nat_interface_is_inside(i) &&
769                       nat_interface_is_outside(i)) ? "in out" :
770                      (nat_interface_is_inside(i) ? "in" : "out"));
771   }
772
773   pool_foreach (i, sm->output_feature_interfaces)
774    {
775     vlib_cli_output (vm, " %U output-feature %s",
776                      format_vnet_sw_if_index_name, vnm,
777                      i->sw_if_index,
778                      (nat_interface_is_inside(i) &&
779                       nat_interface_is_outside(i)) ? "in out" :
780                      (nat_interface_is_inside(i) ? "in" : "out"));
781   }
782
783   return 0;
784 }
785
786 static clib_error_t *
787 add_static_mapping_command_fn (vlib_main_t * vm,
788                                unformat_input_t * input,
789                                vlib_cli_command_t * cmd)
790 {
791   unformat_input_t _line_input, *line_input = &_line_input;
792   clib_error_t *error = 0;
793   ip4_address_t l_addr, e_addr, exact_addr;
794   u32 l_port = 0, e_port = 0, vrf_id = ~0;
795   int is_add = 1, addr_only = 1, rv, exact = 0;
796   u32 sw_if_index = ~0;
797   vnet_main_t *vnm = vnet_get_main ();
798   nat_protocol_t proto = NAT_PROTOCOL_OTHER;
799   u8 proto_set = 0;
800   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
801   u8 out2in_only = 0;
802
803   /* Get a line of input. */
804   if (!unformat_user (input, unformat_line_input, line_input))
805     return 0;
806
807   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
808     {
809       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
810                     &l_port))
811         addr_only = 0;
812       else
813         if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
814         ;
815       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
816                          &e_addr, &e_port))
817         addr_only = 0;
818       else if (unformat (line_input, "external %U", unformat_ip4_address,
819                          &e_addr))
820         ;
821       else if (unformat (line_input, "external %U %u",
822                          unformat_vnet_sw_interface, vnm, &sw_if_index,
823                          &e_port))
824         addr_only = 0;
825       else if (unformat (line_input, "external %U",
826                          unformat_vnet_sw_interface, vnm, &sw_if_index))
827         ;
828       else if (unformat (line_input, "exact %U", unformat_ip4_address,
829                          &exact_addr))
830         exact = 1;
831       else if (unformat (line_input, "vrf %u", &vrf_id))
832         ;
833       else if (unformat (line_input, "%U", unformat_nat_protocol, &proto))
834         proto_set = 1;
835       else if (unformat (line_input, "twice-nat"))
836         twice_nat = TWICE_NAT;
837       else if (unformat (line_input, "self-twice-nat"))
838         twice_nat = TWICE_NAT_SELF;
839       else if (unformat (line_input, "out2in-only"))
840         out2in_only = 1;
841       else if (unformat (line_input, "del"))
842         is_add = 0;
843       else
844         {
845           error = clib_error_return (0, "unknown input: '%U'",
846                                      format_unformat_error, line_input);
847           goto done;
848         }
849     }
850
851   if (twice_nat && addr_only)
852     {
853       error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
854       goto done;
855     }
856
857   if (addr_only)
858     {
859       if (proto_set)
860         {
861           error =
862             clib_error_return (0,
863                                "address only mapping doesn't support protocol");
864           goto done;
865         }
866     }
867   else if (!proto_set)
868     {
869       error = clib_error_return (0, "protocol is required");
870       goto done;
871     }
872
873   rv = snat_add_static_mapping (
874     l_addr, e_addr, clib_host_to_net_u16 (l_port),
875     clib_host_to_net_u16 (e_port), vrf_id, addr_only, sw_if_index, proto,
876     is_add, twice_nat, out2in_only, 0, 0, exact_addr, exact);
877
878   switch (rv)
879     {
880     case VNET_API_ERROR_INVALID_VALUE:
881       error = clib_error_return (0, "External port already in use.");
882       goto done;
883     case VNET_API_ERROR_NO_SUCH_ENTRY:
884       if (is_add)
885         error = clib_error_return (0, "External address must be allocated.");
886       else
887         error = clib_error_return (0, "Mapping not exist.");
888       goto done;
889     case VNET_API_ERROR_NO_SUCH_FIB:
890       error = clib_error_return (0, "No such VRF id.");
891       goto done;
892     case VNET_API_ERROR_VALUE_EXIST:
893       error = clib_error_return (0, "Mapping already exist.");
894       goto done;
895     default:
896       break;
897     }
898
899 done:
900   unformat_free (line_input);
901
902   return error;
903 }
904
905 static clib_error_t *
906 add_identity_mapping_command_fn (vlib_main_t * vm,
907                                  unformat_input_t * input,
908                                  vlib_cli_command_t * cmd)
909 {
910   unformat_input_t _line_input, *line_input = &_line_input;
911   clib_error_t *error = 0;
912   ip4_address_t addr, pool_addr = { 0 };
913   u32 port = 0, vrf_id = ~0;
914   int is_add = 1;
915   int addr_only = 1;
916   u32 sw_if_index = ~0;
917   vnet_main_t *vnm = vnet_get_main ();
918   int rv;
919   nat_protocol_t proto;
920
921   addr.as_u32 = 0;
922
923   /* Get a line of input. */
924   if (!unformat_user (input, unformat_line_input, line_input))
925     return 0;
926
927   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
928     {
929       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
930         ;
931       else if (unformat (line_input, "external %U",
932                          unformat_vnet_sw_interface, vnm, &sw_if_index))
933         ;
934       else if (unformat (line_input, "vrf %u", &vrf_id))
935         ;
936       else if (unformat (line_input, "%U %u", unformat_nat_protocol, &proto,
937                          &port))
938         addr_only = 0;
939       else if (unformat (line_input, "del"))
940         is_add = 0;
941       else
942         {
943           error = clib_error_return (0, "unknown input: '%U'",
944                                      format_unformat_error, line_input);
945           goto done;
946         }
947     }
948
949   rv = snat_add_static_mapping (
950     addr, addr, clib_host_to_net_u16 (port), clib_host_to_net_u16 (port),
951     vrf_id, addr_only, sw_if_index, proto, is_add, 0, 0, 0, 1, pool_addr, 0);
952
953   switch (rv)
954     {
955     case VNET_API_ERROR_INVALID_VALUE:
956       error = clib_error_return (0, "External port already in use.");
957       goto done;
958     case VNET_API_ERROR_NO_SUCH_ENTRY:
959       if (is_add)
960         error = clib_error_return (0, "External address must be allocated.");
961       else
962         error = clib_error_return (0, "Mapping not exist.");
963       goto done;
964     case VNET_API_ERROR_NO_SUCH_FIB:
965       error = clib_error_return (0, "No such VRF id.");
966       goto done;
967     case VNET_API_ERROR_VALUE_EXIST:
968       error = clib_error_return (0, "Mapping already exist.");
969       goto done;
970     default:
971       break;
972     }
973
974 done:
975   unformat_free (line_input);
976
977   return error;
978 }
979
980 static clib_error_t *
981 add_lb_static_mapping_command_fn (vlib_main_t * vm,
982                                   unformat_input_t * input,
983                                   vlib_cli_command_t * cmd)
984 {
985   unformat_input_t _line_input, *line_input = &_line_input;
986   clib_error_t *error = 0;
987   ip4_address_t l_addr, e_addr;
988   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0, affinity = 0;
989   int is_add = 1;
990   int rv;
991   nat_protocol_t proto;
992   u8 proto_set = 0;
993   nat44_lb_addr_port_t *locals = 0, local;
994   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
995   u8 out2in_only = 0;
996
997   /* Get a line of input. */
998   if (!unformat_user (input, unformat_line_input, line_input))
999     return 0;
1000
1001   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1002     {
1003       if (unformat (line_input, "local %U:%u probability %u",
1004                     unformat_ip4_address, &l_addr, &l_port, &probability))
1005         {
1006           clib_memset (&local, 0, sizeof (local));
1007           local.addr = l_addr;
1008           local.port = (u16) l_port;
1009           local.probability = (u8) probability;
1010           vec_add1 (locals, local);
1011         }
1012       else if (unformat (line_input, "local %U:%u vrf %u probability %u",
1013                          unformat_ip4_address, &l_addr, &l_port, &vrf_id,
1014                          &probability))
1015         {
1016           clib_memset (&local, 0, sizeof (local));
1017           local.addr = l_addr;
1018           local.port = (u16) l_port;
1019           local.probability = (u8) probability;
1020           local.vrf_id = vrf_id;
1021           vec_add1 (locals, local);
1022         }
1023       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1024                          &e_addr, &e_port))
1025         ;
1026       else if (unformat (line_input, "protocol %U", unformat_nat_protocol,
1027                          &proto))
1028         proto_set = 1;
1029       else if (unformat (line_input, "twice-nat"))
1030         twice_nat = TWICE_NAT;
1031       else if (unformat (line_input, "self-twice-nat"))
1032         twice_nat = TWICE_NAT_SELF;
1033       else if (unformat (line_input, "out2in-only"))
1034         out2in_only = 1;
1035       else if (unformat (line_input, "del"))
1036         is_add = 0;
1037       else if (unformat (line_input, "affinity %u", &affinity))
1038         ;
1039       else
1040         {
1041           error = clib_error_return (0, "unknown input: '%U'",
1042                                      format_unformat_error, line_input);
1043           goto done;
1044         }
1045     }
1046
1047   if (vec_len (locals) < 2)
1048     {
1049       error = clib_error_return (0, "at least two local must be set");
1050       goto done;
1051     }
1052
1053   if (!proto_set)
1054     {
1055       error = clib_error_return (0, "missing protocol");
1056       goto done;
1057     }
1058
1059   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, locals,
1060                                         is_add, twice_nat, out2in_only, 0,
1061                                         affinity);
1062
1063   switch (rv)
1064     {
1065     case VNET_API_ERROR_INVALID_VALUE:
1066       error = clib_error_return (0, "External port already in use.");
1067       goto done;
1068     case VNET_API_ERROR_NO_SUCH_ENTRY:
1069       if (is_add)
1070         error = clib_error_return (0, "External address must be allocated.");
1071       else
1072         error = clib_error_return (0, "Mapping not exist.");
1073       goto done;
1074     case VNET_API_ERROR_VALUE_EXIST:
1075       error = clib_error_return (0, "Mapping already exist.");
1076       goto done;
1077     default:
1078       break;
1079     }
1080
1081 done:
1082   unformat_free (line_input);
1083   vec_free (locals);
1084
1085   return error;
1086 }
1087
1088 static clib_error_t *
1089 add_lb_backend_command_fn (vlib_main_t * vm,
1090                            unformat_input_t * input, vlib_cli_command_t * cmd)
1091 {
1092   unformat_input_t _line_input, *line_input = &_line_input;
1093   clib_error_t *error = 0;
1094   ip4_address_t l_addr, e_addr;
1095   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
1096   int is_add = 1;
1097   int rv;
1098   nat_protocol_t proto;
1099   u8 proto_set = 0;
1100
1101   /* Get a line of input. */
1102   if (!unformat_user (input, unformat_line_input, line_input))
1103     return 0;
1104
1105   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1106     {
1107       if (unformat (line_input, "local %U:%u probability %u",
1108                     unformat_ip4_address, &l_addr, &l_port, &probability))
1109         ;
1110       else if (unformat (line_input, "local %U:%u vrf %u probability %u",
1111                          unformat_ip4_address, &l_addr, &l_port, &vrf_id,
1112                          &probability))
1113         ;
1114       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1115                          &e_addr, &e_port))
1116         ;
1117       else if (unformat (line_input, "protocol %U", unformat_nat_protocol,
1118                          &proto))
1119         proto_set = 1;
1120       else if (unformat (line_input, "del"))
1121         is_add = 0;
1122       else
1123         {
1124           error = clib_error_return (0, "unknown input: '%U'",
1125                                      format_unformat_error, line_input);
1126           goto done;
1127         }
1128     }
1129
1130   if (!l_port || !e_port)
1131     {
1132       error = clib_error_return (0, "local or external must be set");
1133       goto done;
1134     }
1135
1136   if (!proto_set)
1137     {
1138       error = clib_error_return (0, "missing protocol");
1139       goto done;
1140     }
1141
1142   rv =
1143     nat44_lb_static_mapping_add_del_local (e_addr, (u16) e_port, l_addr,
1144                                            l_port, proto, vrf_id, probability,
1145                                            is_add);
1146
1147   switch (rv)
1148     {
1149     case VNET_API_ERROR_INVALID_VALUE:
1150       error = clib_error_return (0, "External is not load-balancing static "
1151                                  "mapping.");
1152       goto done;
1153     case VNET_API_ERROR_NO_SUCH_ENTRY:
1154       error = clib_error_return (0, "Mapping or back-end not exist.");
1155       goto done;
1156     case VNET_API_ERROR_VALUE_EXIST:
1157       error = clib_error_return (0, "Back-end already exist.");
1158       goto done;
1159     case VNET_API_ERROR_UNSPECIFIED:
1160       error = clib_error_return (0, "At least two back-ends must remain");
1161       goto done;
1162     default:
1163       break;
1164     }
1165
1166 done:
1167   unformat_free (line_input);
1168
1169   return error;
1170 }
1171
1172 static clib_error_t *
1173 nat44_show_static_mappings_command_fn (vlib_main_t * vm,
1174                                        unformat_input_t * input,
1175                                        vlib_cli_command_t * cmd)
1176 {
1177   snat_main_t *sm = &snat_main;
1178   snat_static_mapping_t *m;
1179   snat_static_map_resolve_t *rp;
1180
1181   vlib_cli_output (vm, "NAT44 static mappings:");
1182   pool_foreach (m, sm->static_mappings)
1183    {
1184     vlib_cli_output (vm, " %U", format_snat_static_mapping, m);
1185   }
1186   vec_foreach (rp, sm->to_resolve)
1187     vlib_cli_output (vm, " %U", format_snat_static_map_to_resolve, rp);
1188
1189   return 0;
1190 }
1191
1192 static clib_error_t *
1193 snat_add_interface_address_command_fn (vlib_main_t * vm,
1194                                        unformat_input_t * input,
1195                                        vlib_cli_command_t * cmd)
1196 {
1197   snat_main_t *sm = &snat_main;
1198   unformat_input_t _line_input, *line_input = &_line_input;
1199   u32 sw_if_index;
1200   int rv;
1201   int is_del = 0;
1202   clib_error_t *error = 0;
1203   u8 twice_nat = 0;
1204
1205   /* Get a line of input. */
1206   if (!unformat_user (input, unformat_line_input, line_input))
1207     return 0;
1208
1209   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1210     {
1211       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
1212                     sm->vnet_main, &sw_if_index))
1213         ;
1214       else if (unformat (line_input, "twice-nat"))
1215         twice_nat = 1;
1216       else if (unformat (line_input, "del"))
1217         is_del = 1;
1218       else
1219         {
1220           error = clib_error_return (0, "unknown input '%U'",
1221                                      format_unformat_error, line_input);
1222           goto done;
1223         }
1224     }
1225
1226   rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
1227
1228   switch (rv)
1229     {
1230     case 0:
1231       break;
1232
1233     default:
1234       error = clib_error_return (0, "snat_add_interface_address returned %d",
1235                                  rv);
1236       goto done;
1237     }
1238
1239 done:
1240   unformat_free (line_input);
1241
1242   return error;
1243 }
1244
1245 static clib_error_t *
1246 nat44_show_interface_address_command_fn (vlib_main_t * vm,
1247                                          unformat_input_t * input,
1248                                          vlib_cli_command_t * cmd)
1249 {
1250   snat_main_t *sm = &snat_main;
1251   vnet_main_t *vnm = vnet_get_main ();
1252   u32 *sw_if_index;
1253
1254   vlib_cli_output (vm, "NAT44 pool address interfaces:");
1255   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
1256     {
1257       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
1258                        *sw_if_index);
1259     }
1260   vlib_cli_output (vm, "NAT44 twice-nat pool address interfaces:");
1261   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat)
1262     {
1263       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
1264                        *sw_if_index);
1265     }
1266
1267   return 0;
1268 }
1269
1270 static clib_error_t *
1271 nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
1272                                 vlib_cli_command_t * cmd)
1273 {
1274   unformat_input_t _line_input, *line_input = &_line_input;
1275   clib_error_t *error = 0;
1276   snat_main_per_thread_data_t *tsm;
1277   snat_main_t *sm = &snat_main;
1278
1279   int i = 0;
1280
1281   if (!unformat_user (input, unformat_line_input, line_input))
1282     goto print;
1283
1284   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1285     {
1286       error = clib_error_return (0, "unknown input '%U'",
1287                                  format_unformat_error, line_input);
1288       break;
1289     }
1290   unformat_free (line_input);
1291
1292 print:
1293     vlib_cli_output (vm, "NAT44 ED sessions:");
1294
1295   vec_foreach_index (i, sm->per_thread_data)
1296     {
1297       tsm = vec_elt_at_index (sm->per_thread_data, i);
1298
1299       vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n",
1300                        i, vlib_worker_threads[i].name,
1301                        pool_elts (tsm->sessions));
1302
1303           snat_session_t *s;
1304           pool_foreach (s, tsm->sessions)
1305            {
1306             vlib_cli_output (vm, "  %U\n", format_snat_session, tsm, s);
1307           }
1308     }
1309   return error;
1310 }
1311
1312 static clib_error_t *
1313 nat44_set_session_limit_command_fn (vlib_main_t * vm,
1314                                     unformat_input_t * input,
1315                                     vlib_cli_command_t * cmd)
1316 {
1317   unformat_input_t _line_input, *line_input = &_line_input;
1318   clib_error_t *error = 0;
1319
1320   u32 session_limit = 0, vrf_id = 0;
1321
1322   /* Get a line of input. */
1323   if (!unformat_user (input, unformat_line_input, line_input))
1324     return 0;
1325
1326   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1327     {
1328       if (unformat (line_input, "%u", &session_limit))
1329         ;
1330       else if (unformat (line_input, "vrf %u", &vrf_id))
1331         ;
1332       else
1333         {
1334           error = clib_error_return (0, "unknown input '%U'",
1335                                      format_unformat_error, line_input);
1336           goto done;
1337         }
1338     }
1339
1340   if (!session_limit)
1341     error = clib_error_return (0, "missing value of session limit");
1342   else if (nat44_update_session_limit (session_limit, vrf_id))
1343     error = clib_error_return (0, "nat44_set_session_limit failed");
1344
1345 done:
1346   unformat_free (line_input);
1347
1348   return error;
1349 }
1350
1351 static clib_error_t *
1352 nat44_del_session_command_fn (vlib_main_t * vm,
1353                               unformat_input_t * input,
1354                               vlib_cli_command_t * cmd)
1355 {
1356   snat_main_t *sm = &snat_main;
1357   unformat_input_t _line_input, *line_input = &_line_input;
1358   u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
1359   clib_error_t *error = 0;
1360   ip4_address_t addr, eh_addr;
1361   nat_protocol_t proto;
1362   int is_in = 0;
1363   int rv;
1364
1365   /* Get a line of input. */
1366   if (!unformat_user (input, unformat_line_input, line_input))
1367     return 0;
1368
1369   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1370     {
1371       if (unformat
1372           (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
1373            unformat_nat_protocol, &proto))
1374         ;
1375       else if (unformat (line_input, "in"))
1376         {
1377           is_in = 1;
1378           vrf_id = sm->inside_vrf_id;
1379         }
1380       else if (unformat (line_input, "out"))
1381         {
1382           is_in = 0;
1383           vrf_id = sm->outside_vrf_id;
1384         }
1385       else if (unformat (line_input, "vrf %u", &vrf_id))
1386         ;
1387       else if (unformat (line_input, "external-host %U:%u",
1388                          unformat_ip4_address, &eh_addr, &eh_port))
1389         ;
1390       else
1391         {
1392           error = clib_error_return (0, "unknown input '%U'",
1393                                      format_unformat_error, line_input);
1394           goto done;
1395         }
1396     }
1397
1398     rv =
1399       nat44_del_ed_session (sm, &addr, clib_host_to_net_u16 (port), &eh_addr,
1400                             clib_host_to_net_u16 (eh_port),
1401                             nat_proto_to_ip_proto (proto), vrf_id, is_in);
1402
1403   switch (rv)
1404     {
1405     case 0:
1406       break;
1407
1408     default:
1409       error = clib_error_return (0, "nat44_del_session returned %d", rv);
1410       goto done;
1411     }
1412
1413 done:
1414   unformat_free (line_input);
1415
1416   return error;
1417 }
1418
1419 static clib_error_t *
1420 snat_forwarding_set_command_fn (vlib_main_t * vm,
1421                                 unformat_input_t * input,
1422                                 vlib_cli_command_t * cmd)
1423 {
1424   snat_main_t *sm = &snat_main;
1425   unformat_input_t _line_input, *line_input = &_line_input;
1426   u8 forwarding_enable;
1427   u8 forwarding_enable_set = 0;
1428   clib_error_t *error = 0;
1429
1430   /* Get a line of input. */
1431   if (!unformat_user (input, unformat_line_input, line_input))
1432     return clib_error_return (0, "'enable' or 'disable' expected");
1433
1434   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1435     {
1436       if (!forwarding_enable_set && unformat (line_input, "enable"))
1437         {
1438           forwarding_enable = 1;
1439           forwarding_enable_set = 1;
1440         }
1441       else if (!forwarding_enable_set && unformat (line_input, "disable"))
1442         {
1443           forwarding_enable = 0;
1444           forwarding_enable_set = 1;
1445         }
1446       else
1447         {
1448           error = clib_error_return (0, "unknown input '%U'",
1449                                      format_unformat_error, line_input);
1450           goto done;
1451         }
1452     }
1453
1454   if (!forwarding_enable_set)
1455     {
1456       error = clib_error_return (0, "'enable' or 'disable' expected");
1457       goto done;
1458     }
1459
1460   sm->forwarding_enabled = forwarding_enable;
1461
1462 done:
1463   unformat_free (line_input);
1464
1465   return error;
1466 }
1467
1468 static clib_error_t *
1469 set_timeout_command_fn (vlib_main_t * vm,
1470                         unformat_input_t * input, vlib_cli_command_t * cmd)
1471 {
1472   snat_main_t *sm = &snat_main;
1473   unformat_input_t _line_input, *line_input = &_line_input;
1474   clib_error_t *error = 0;
1475
1476   /* Get a line of input. */
1477   if (!unformat_user (input, unformat_line_input, line_input))
1478     return 0;
1479
1480   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1481     {
1482       if (unformat (line_input, "udp %u", &sm->timeouts.udp));
1483       else if (unformat (line_input, "tcp-established %u",
1484                          &sm->timeouts.tcp.established));
1485       else if (unformat (line_input, "tcp-transitory %u",
1486                          &sm->timeouts.tcp.transitory));
1487       else if (unformat (line_input, "icmp %u", &sm->timeouts.icmp));
1488       else if (unformat (line_input, "reset"))
1489         nat_reset_timeouts (&sm->timeouts);
1490       else
1491         {
1492           error = clib_error_return (0, "unknown input '%U'",
1493                                      format_unformat_error, line_input);
1494           goto done;
1495         }
1496     }
1497 done:
1498   unformat_free (line_input);
1499   return error;
1500 }
1501
1502 static clib_error_t *
1503 nat_show_timeouts_command_fn (vlib_main_t * vm,
1504                               unformat_input_t * input,
1505                               vlib_cli_command_t * cmd)
1506 {
1507   snat_main_t *sm = &snat_main;
1508
1509   vlib_cli_output (vm, "udp timeout: %dsec", sm->timeouts.udp);
1510   vlib_cli_output (vm, "tcp-established timeout: %dsec",
1511                    sm->timeouts.tcp.established);
1512   vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
1513                    sm->timeouts.tcp.transitory);
1514   vlib_cli_output (vm, "icmp timeout: %dsec", sm->timeouts.icmp);
1515
1516   return 0;
1517 }
1518
1519 static clib_error_t *
1520 set_frame_queue_nelts_command_fn (vlib_main_t *vm, unformat_input_t *input,
1521                                   vlib_cli_command_t *cmd)
1522 {
1523   unformat_input_t _line_input, *line_input = &_line_input;
1524   clib_error_t *error = 0;
1525   u32 frame_queue_nelts = 0;
1526   /* Get a line of input. */
1527   if (!unformat_user (input, unformat_line_input, line_input))
1528     return 0;
1529   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1530     {
1531       if (unformat (line_input, "%u", &frame_queue_nelts))
1532         ;
1533       else
1534         {
1535           error = clib_error_return (0, "unknown input '%U'",
1536                                      format_unformat_error, line_input);
1537           goto done;
1538         }
1539     }
1540   if (!frame_queue_nelts)
1541     {
1542       error = clib_error_return (0, "frame_queue_nelts cannot be zero");
1543       goto done;
1544     }
1545   if (snat_set_frame_queue_nelts (frame_queue_nelts) != 0)
1546     {
1547       error = clib_error_return (0, "snat_set_frame_queue_nelts failed");
1548       goto done;
1549     }
1550 done:
1551   unformat_free (line_input);
1552   return error;
1553 }
1554
1555 /*?
1556  * @cliexpar
1557  * @cliexstart{nat44 enable}
1558  * Enable nat44 plugin
1559  * To enable nat44, use:
1560  *  vpp# nat44 enable sessions <n>
1561  * To enable nat44 static mapping only, use:
1562  *  vpp# nat44 enable sessions <n> static-mapping
1563  * To enable nat44 static mapping with connection tracking, use:
1564  *  vpp# nat44 enable sessions <n> static-mapping connection-tracking
1565  * To set inside-vrf outside-vrf, use:
1566  *  vpp# nat44 enable sessions <n> inside-vrf <id> outside-vrf <id>
1567  * @cliexend
1568 ?*/
1569 VLIB_CLI_COMMAND (nat44_enable_command, static) = {
1570   .path = "nat44 enable",
1571   .short_help =
1572     "nat44 enable sessions <max-number> [static-mappig-only "
1573     "[connection-tracking]] [inside-vrf <vrf-id>] [outside-vrf <vrf-id>]",
1574   .function = nat44_enable_command_fn,
1575 };
1576
1577 /*?
1578  * @cliexpar
1579  * @cliexstart{nat44 disable}
1580  * Disable nat44 plugin
1581  * To disable nat44, use:
1582  *  vpp# nat44 disable
1583  * @cliexend
1584 ?*/
1585 VLIB_CLI_COMMAND (nat44_disable_command, static) = {
1586   .path = "nat44 disable",
1587   .short_help = "nat44 disable",
1588   .function = nat44_disable_command_fn,
1589 };
1590
1591 /*?
1592  * @cliexpar
1593  * @cliexstart{set snat workers}
1594  * Set NAT workers if 2 or more workers available, use:
1595  *  vpp# set snat workers 0-2,5
1596  * @cliexend
1597 ?*/
1598 VLIB_CLI_COMMAND (set_workers_command, static) = {
1599   .path = "set nat workers",
1600   .function = set_workers_command_fn,
1601   .short_help = "set nat workers <workers-list>",
1602 };
1603
1604 /*?
1605  * @cliexpar
1606  * @cliexstart{show nat workers}
1607  * Show NAT workers.
1608  *  vpp# show nat workers:
1609  *  2 workers
1610  *    vpp_wk_0
1611  *    vpp_wk_1
1612  * @cliexend
1613 ?*/
1614 VLIB_CLI_COMMAND (nat_show_workers_command, static) = {
1615   .path = "show nat workers",
1616   .short_help = "show nat workers",
1617   .function = nat_show_workers_commnad_fn,
1618 };
1619
1620 /*?
1621  * @cliexpar
1622  * @cliexstart{set nat timeout}
1623  * Set values of timeouts for NAT sessions (in seconds), use:
1624  *  vpp# set nat timeout udp 120 tcp-established 7500 tcp-transitory 250 icmp 90
1625  * To reset default values use:
1626  *  vpp# set nat timeout reset
1627  * @cliexend
1628 ?*/
1629 VLIB_CLI_COMMAND (set_timeout_command, static) = {
1630   .path = "set nat timeout",
1631   .function = set_timeout_command_fn,
1632   .short_help =
1633     "set nat timeout [udp <sec> | tcp-established <sec> "
1634     "tcp-transitory <sec> | icmp <sec> | reset]",
1635 };
1636
1637 /*?
1638  * @cliexpar
1639  * @cliexstart{show nat timeouts}
1640  * Show values of timeouts for NAT sessions.
1641  * vpp# show nat timeouts
1642  * udp timeout: 300sec
1643  * tcp-established timeout: 7440sec
1644  * tcp-transitory timeout: 240sec
1645  * icmp timeout: 60sec
1646  * @cliexend
1647 ?*/
1648 VLIB_CLI_COMMAND (nat_show_timeouts_command, static) = {
1649   .path = "show nat timeouts",
1650   .short_help = "show nat timeouts",
1651   .function = nat_show_timeouts_command_fn,
1652 };
1653
1654 /*?
1655  * @cliexpar
1656  * @cliexstart{set nat frame-queue-nelts}
1657  * Set number of worker handoff frame queue elements.
1658  * @cliexend
1659 ?*/
1660 VLIB_CLI_COMMAND (set_frame_queue_nelts_command, static) = {
1661   .path = "set nat frame-queue-nelts",
1662   .function = set_frame_queue_nelts_command_fn,
1663   .short_help = "set nat frame-queue-nelts <number>",
1664 };
1665
1666 /*?
1667  * @cliexpar
1668  * @cliexstart{nat set logging level}
1669  * To set NAT logging level use:
1670  * Set nat logging level
1671  * @cliexend
1672 ?*/
1673 VLIB_CLI_COMMAND (snat_set_log_level_command, static) = {
1674   .path = "nat set logging level",
1675   .function = snat_set_log_level_command_fn,
1676   .short_help = "nat set logging level <level>",
1677 };
1678
1679 /*?
1680  * @cliexpar
1681  * @cliexstart{snat ipfix logging}
1682  * To enable NAT IPFIX logging use:
1683  *  vpp# nat ipfix logging
1684  * To set IPFIX exporter use:
1685  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
1686  * @cliexend
1687 ?*/
1688 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
1689   .path = "nat ipfix logging",
1690   .function = snat_ipfix_logging_enable_disable_command_fn,
1691   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
1692 };
1693
1694 /*?
1695  * @cliexpar
1696  * @cliexstart{nat mss-clamping}
1697  * Set TCP MSS rewriting configuration
1698  * To enable TCP MSS rewriting use:
1699  *  vpp# nat mss-clamping 1452
1700  * To disbale TCP MSS rewriting use:
1701  *  vpp# nat mss-clamping disable
1702  * @cliexend
1703 ?*/
1704 VLIB_CLI_COMMAND (nat_set_mss_clamping_command, static) = {
1705     .path = "nat mss-clamping",
1706     .short_help = "nat mss-clamping <mss-value>|disable",
1707     .function = nat_set_mss_clamping_command_fn,
1708 };
1709
1710 /*?
1711  * @cliexpar
1712  * @cliexstart{show nat mss-clamping}
1713  * Show TCP MSS rewriting configuration
1714  * @cliexend
1715 ?*/
1716 VLIB_CLI_COMMAND (nat_show_mss_clamping_command, static) = {
1717     .path = "show nat mss-clamping",
1718     .short_help = "show nat mss-clamping",
1719     .function = nat_show_mss_clamping_command_fn,
1720 };
1721
1722 /*?
1723  * @cliexpar
1724  * @cliexstart{show nat44 hash tables}
1725  * Show NAT44 hash tables
1726  * @cliexend
1727 ?*/
1728 VLIB_CLI_COMMAND (nat44_show_hash, static) = {
1729   .path = "show nat44 hash tables",
1730   .short_help = "show nat44 hash tables [detail|verbose]",
1731   .function = nat44_show_hash_command_fn,
1732 };
1733
1734 /*?
1735  * @cliexpar
1736  * @cliexstart{nat44 add address}
1737  * Add/delete NAT44 pool address.
1738  * To add NAT44 pool address use:
1739  *  vpp# nat44 add address 172.16.1.3
1740  *  vpp# nat44 add address 172.16.2.2 - 172.16.2.24
1741  * To add NAT44 pool address for specific tenant (identified by VRF id) use:
1742  *  vpp# nat44 add address 172.16.1.3 tenant-vrf 10
1743  * @cliexend
1744 ?*/
1745 VLIB_CLI_COMMAND (add_address_command, static) = {
1746   .path = "nat44 add address",
1747   .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1748                 "[tenant-vrf <vrf-id>] [twice-nat] [del]",
1749   .function = add_address_command_fn,
1750 };
1751
1752 /*?
1753  * @cliexpar
1754  * @cliexstart{show nat44 summary}
1755  * Show NAT44 summary
1756  * vpp# show nat44 summary
1757  * @cliexend
1758 ?*/
1759 VLIB_CLI_COMMAND (nat44_show_summary_command, static) = {
1760   .path = "show nat44 summary",
1761   .short_help = "show nat44 summary",
1762   .function = nat44_show_summary_command_fn,
1763 };
1764
1765 /*?
1766  * @cliexpar
1767  * @cliexstart{show nat44 addresses}
1768  * Show NAT44 pool addresses.
1769  * vpp# show nat44 addresses
1770  * NAT44 pool addresses:
1771  * 172.16.2.2
1772  *   tenant VRF independent
1773  *   10 busy udp ports
1774  *   0 busy tcp ports
1775  *   0 busy icmp ports
1776  * 172.16.1.3
1777  *   tenant VRF: 10
1778  *   0 busy udp ports
1779  *   2 busy tcp ports
1780  *   0 busy icmp ports
1781  * NAT44 twice-nat pool addresses:
1782  * 10.20.30.72
1783  *   tenant VRF independent
1784  *   0 busy udp ports
1785  *   0 busy tcp ports
1786  *   0 busy icmp ports
1787  * @cliexend
1788 ?*/
1789 VLIB_CLI_COMMAND (nat44_show_addresses_command, static) = {
1790   .path = "show nat44 addresses",
1791   .short_help = "show nat44 addresses",
1792   .function = nat44_show_addresses_command_fn,
1793 };
1794
1795 /*?
1796  * @cliexpar
1797  * @cliexstart{set interface nat44}
1798  * Enable/disable NAT44 feature on the interface.
1799  * To enable NAT44 feature with local network interface use:
1800  *  vpp# set interface nat44 in GigabitEthernet0/8/0
1801  * To enable NAT44 feature with external network interface use:
1802  *  vpp# set interface nat44 out GigabitEthernet0/a/0
1803  * @cliexend
1804 ?*/
1805 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1806   .path = "set interface nat44",
1807   .function = snat_feature_command_fn,
1808   .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1809                 "[del]",
1810 };
1811
1812 /*?
1813  * @cliexpar
1814  * @cliexstart{show nat44 interfaces}
1815  * Show interfaces with NAT44 feature.
1816  * vpp# show nat44 interfaces
1817  * NAT44 interfaces:
1818  *  GigabitEthernet0/8/0 in
1819  *  GigabitEthernet0/a/0 out
1820  * @cliexend
1821 ?*/
1822 VLIB_CLI_COMMAND (nat44_show_interfaces_command, static) = {
1823   .path = "show nat44 interfaces",
1824   .short_help = "show nat44 interfaces",
1825   .function = nat44_show_interfaces_command_fn,
1826 };
1827
1828 /*?
1829  * @cliexpar
1830  * @cliexstart{nat44 add static mapping}
1831  * Static mapping allows hosts on the external network to initiate connection
1832  * to to the local network host.
1833  * To create static mapping between local host address 10.0.0.3 port 6303 and
1834  * external address 4.4.4.4 port 3606 for TCP protocol use:
1835  *  vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
1836  * If not runnig "static mapping only" NAT plugin mode use before:
1837  *  vpp# nat44 add address 4.4.4.4
1838  * To create address only static mapping between local and external address use:
1839  *  vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
1840  * To create ICMP static mapping between local and external with ICMP echo
1841  * identifier 10 use:
1842  *  vpp# nat44 add static mapping icmp local 10.0.0.3 10 external 4.4.4.4 10
1843  * To force use of specific pool address, vrf independent
1844  *  vpp# nat44 add static mapping local 10.0.0.2 1234 external 10.0.2.2 1234 twice-nat exact 10.0.1.2
1845  * @cliexend
1846 ?*/
1847 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1848   .path = "nat44 add static mapping",
1849   .function = add_static_mapping_command_fn,
1850   .short_help =
1851     "nat44 add static mapping tcp|udp|icmp local <addr> [<port|icmp-echo-id>] "
1852     "external <addr> [<port|icmp-echo-id>] [vrf <table-id>] [twice-nat|self-twice-nat] "
1853     "[out2in-only] [exact <pool-addr>] [del]",
1854 };
1855
1856 /*?
1857  * @cliexpar
1858  * @cliexstart{nat44 add identity mapping}
1859  * Identity mapping translate an IP address to itself.
1860  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
1861  * use:
1862  *  vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
1863  * To create identity mapping for address 10.0.0.3 use:
1864  *  vpp# nat44 add identity mapping 10.0.0.3
1865  * To create identity mapping for DHCP addressed interface use:
1866  *  vpp# nat44 add identity mapping external GigabitEthernet0/a/0 tcp 3606
1867  * @cliexend
1868 ?*/
1869 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
1870   .path = "nat44 add identity mapping",
1871   .function = add_identity_mapping_command_fn,
1872   .short_help = "nat44 add identity mapping <ip4-addr>|external <interface> "
1873     "[<protocol> <port>] [vrf <table-id>] [del]",
1874 };
1875
1876 /*?
1877  * @cliexpar
1878  * @cliexstart{nat44 add load-balancing static mapping}
1879  * Service load balancing using NAT44
1880  * To add static mapping with load balancing for service with external IP
1881  * address 1.2.3.4 and TCP port 80 and mapped to 2 local servers
1882  * 10.100.10.10:8080 and 10.100.10.20:8080 with probability 80% resp. 20% use:
1883  *  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
1884  * @cliexend
1885 ?*/
1886 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
1887   .path = "nat44 add load-balancing static mapping",
1888   .function = add_lb_static_mapping_command_fn,
1889   .short_help =
1890     "nat44 add load-balancing static mapping protocol tcp|udp "
1891     "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
1892     "probability <n> [twice-nat|self-twice-nat] [out2in-only] "
1893     "[affinity <timeout-seconds>] [del]",
1894 };
1895
1896 /*?
1897  * @cliexpar
1898  * @cliexstart{nat44 add load-balancing static mapping}
1899  * Modify service load balancing using NAT44
1900  * To add new back-end server 10.100.10.30:8080 for service load balancing
1901  * static mapping with external IP address 1.2.3.4 and TCP port 80 use:
1902  *  vpp# nat44 add load-balancing back-end protocol tcp external 1.2.3.4:80 local 10.100.10.30:8080 probability 25
1903  * @cliexend
1904 ?*/
1905 VLIB_CLI_COMMAND (add_lb_backend_command, static) = {
1906   .path = "nat44 add load-balancing back-end",
1907   .function = add_lb_backend_command_fn,
1908   .short_help =
1909     "nat44 add load-balancing back-end protocol tcp|udp "
1910     "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
1911     "probability <n> [del]",
1912 };
1913
1914 /*?
1915  * @cliexpar
1916  * @cliexstart{show nat44 static mappings}
1917  * Show NAT44 static mappings.
1918  * vpp# show nat44 static mappings
1919  * NAT44 static mappings:
1920  *  local 10.0.0.3 external 4.4.4.4 vrf 0
1921  *  tcp local 192.168.0.4:6303 external 4.4.4.3:3606 vrf 0
1922  *  tcp vrf 0 external 1.2.3.4:80  out2in-only
1923  *   local 10.100.10.10:8080 probability 80
1924  *   local 10.100.10.20:8080 probability 20
1925  *  tcp local 10.100.3.8:8080 external 169.10.10.1:80 vrf 0 twice-nat
1926  *  tcp local 10.0.0.10:3603 external GigabitEthernet0/a/0:6306 vrf 10
1927  * @cliexend
1928 ?*/
1929 VLIB_CLI_COMMAND (nat44_show_static_mappings_command, static) = {
1930   .path = "show nat44 static mappings",
1931   .short_help = "show nat44 static mappings",
1932   .function = nat44_show_static_mappings_command_fn,
1933 };
1934
1935 /*?
1936  * @cliexpar
1937  * @cliexstart{nat44 add interface address}
1938  * Use NAT44 pool address from specific interfce
1939  * To add NAT44 pool address from specific interface use:
1940  *  vpp# nat44 add interface address GigabitEthernet0/8/0
1941  * @cliexend
1942 ?*/
1943 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
1944     .path = "nat44 add interface address",
1945     .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
1946     .function = snat_add_interface_address_command_fn,
1947 };
1948
1949 /*?
1950  * @cliexpar
1951  * @cliexstart{show nat44 interface address}
1952  * Show NAT44 pool address interfaces
1953  * vpp# show nat44 interface address
1954  * NAT44 pool address interfaces:
1955  *  GigabitEthernet0/a/0
1956  * NAT44 twice-nat pool address interfaces:
1957  *  GigabitEthernet0/8/0
1958  * @cliexend
1959 ?*/
1960 VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = {
1961   .path = "show nat44 interface address",
1962   .short_help = "show nat44 interface address",
1963   .function = nat44_show_interface_address_command_fn,
1964 };
1965
1966 /*?
1967  * @cliexpar
1968  * @cliexstart{show nat44 sessions}
1969  * Show NAT44 sessions.
1970  * @cliexend
1971 ?*/
1972 VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
1973   .path = "show nat44 sessions",
1974   .short_help = "show nat44 sessions [detail|metrics]",
1975   .function = nat44_show_sessions_command_fn,
1976 };
1977
1978 /*?
1979  * @cliexpar
1980  * @cliexstart{set nat44 session limit}
1981  * Set NAT44 session limit.
1982  * @cliexend
1983 ?*/
1984 VLIB_CLI_COMMAND (nat44_set_session_limit_command, static) = {
1985   .path = "set nat44 session limit",
1986   .short_help = "set nat44 session limit <limit> [vrf <table-id>]",
1987   .function = nat44_set_session_limit_command_fn,
1988 };
1989
1990 /*?
1991  * @cliexpar
1992  * @cliexstart{nat44 del session}
1993  * To administratively delete NAT44 session by inside address and port use:
1994  *  vpp# nat44 del session in 10.0.0.3:6303 tcp
1995  * To administratively delete NAT44 session by outside address and port use:
1996  *  vpp# nat44 del session out 1.0.0.3:6033 udp
1997  * @cliexend
1998 ?*/
1999 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
2000     .path = "nat44 del session",
2001     .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>] [external-host <addr>:<port>]",
2002     .function = nat44_del_session_command_fn,
2003 };
2004
2005 /*?
2006  * @cliexpar
2007  * @cliexstart{nat44 forwarding}
2008  * Enable or disable forwarding
2009  * Forward packets which don't match existing translation
2010  * or static mapping instead of dropping them.
2011  * To enable forwarding, use:
2012  *  vpp# nat44 forwarding enable
2013  * To disable forwarding, use:
2014  *  vpp# nat44 forwarding disable
2015  * @cliexend
2016 ?*/
2017 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
2018   .path = "nat44 forwarding",
2019   .short_help = "nat44 forwarding enable|disable",
2020   .function = snat_forwarding_set_command_fn,
2021 };
2022
2023 /*
2024  * fd.io coding-style-patch-verification: ON
2025  *
2026  * Local Variables:
2027  * eval: (c-set-style "gnu")
2028  * End:
2029  */