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