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