NAT: VPP-1531 api cleanup & update
[vpp.git] / src / plugins / nat / nat_test.c
1
2 /*
3  * nat.c - skeleton vpp-api-test plug-in
4  *
5  * Copyright (c) <current-year> <your-organization>
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #include <vat/vat.h>
19 #include <vlibapi/api.h>
20 #include <vlibmemory/api.h>
21
22 #include <vppinfra/error.h>
23 #include <vnet/ip/ip.h>
24 #include <nat/nat.h>
25
26 #define __plugin_msg_base snat_test_main.msg_id_base
27 #include <vlibapi/vat_helper_macros.h>
28
29 uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
30
31 /* Declare message IDs */
32 #include <nat/nat_msg_enum.h>
33
34 /* define message structures */
35 #define vl_typedefs
36 #include <nat/nat_all_api_h.h>
37 #undef vl_typedefs
38
39 /* declare message handlers for each api */
40
41 #define vl_endianfun             /* define message structures */
42 #include <nat/nat_all_api_h.h>
43 #undef vl_endianfun
44
45 /* instantiate all the print functions we know about */
46 #define vl_print(handle, ...)
47 #define vl_printfun
48 #include <nat/nat_all_api_h.h>
49 #undef vl_printfun
50
51 /* Get the API version number. */
52 #define vl_api_version(n,v) static u32 api_version=(v);
53 #include <nat/nat_all_api_h.h>
54 #undef vl_api_version
55
56 typedef struct {
57     /* API message ID base */
58     u16 msg_id_base;
59     vat_main_t *vat_main;
60 } snat_test_main_t;
61
62 snat_test_main_t snat_test_main;
63
64 #define foreach_standard_reply_retval_handler    \
65 _(nat44_add_del_address_range_reply)             \
66 _(nat44_interface_add_del_feature_reply)         \
67 _(nat44_add_del_static_mapping_reply)            \
68 _(nat_set_workers_reply)                         \
69 _(nat44_add_del_interface_addr_reply)            \
70 _(nat_ipfix_enable_disable_reply)                \
71 _(nat_det_add_del_map_reply)                     \
72 _(nat_set_timeouts_reply)                        \
73 _(nat_det_close_session_out_reply)               \
74 _(nat_det_close_session_in_reply)
75
76 #define _(n)                                            \
77     static void vl_api_##n##_t_handler                  \
78     (vl_api_##n##_t * mp)                               \
79     {                                                   \
80         vat_main_t * vam = snat_test_main.vat_main;   \
81         i32 retval = ntohl(mp->retval);                 \
82         if (vam->async_mode) {                          \
83             vam->async_errors += (retval < 0);          \
84         } else {                                        \
85             vam->retval = retval;                       \
86             vam->result_ready = 1;                      \
87         }                                               \
88     }
89 foreach_standard_reply_retval_handler;
90 #undef _
91
92 /*
93  * Table of message reply handlers, must include boilerplate handlers
94  * we just generated
95  */
96 #define foreach_vpe_api_reply_msg                               \
97 _(NAT44_ADD_DEL_ADDRESS_RANGE_REPLY,                            \
98   nat44_add_del_address_range_reply)                            \
99 _(NAT44_INTERFACE_ADD_DEL_FEATURE_REPLY,                        \
100   nat44_interface_add_del_feature_reply)                        \
101 _(NAT44_ADD_DEL_STATIC_MAPPING_REPLY,                           \
102   nat44_add_del_static_mapping_reply)                           \
103 _(NAT_CONTROL_PING_REPLY, nat_control_ping_reply)               \
104 _(NAT44_STATIC_MAPPING_DETAILS, nat44_static_mapping_details)   \
105 _(NAT_SHOW_CONFIG_REPLY, nat_show_config_reply)                 \
106 _(NAT44_ADDRESS_DETAILS, nat44_address_details)                 \
107 _(NAT44_INTERFACE_DETAILS, nat44_interface_details)             \
108 _(NAT_SET_WORKERS_REPLY, nat_set_workers_reply)                 \
109 _(NAT_WORKER_DETAILS, nat_worker_details)                       \
110 _(NAT44_ADD_DEL_INTERFACE_ADDR_REPLY,                           \
111   nat44_add_del_interface_addr_reply)                           \
112 _(NAT44_INTERFACE_ADDR_DETAILS, nat44_interface_addr_details)   \
113 _(NAT_IPFIX_ENABLE_DISABLE_REPLY,                               \
114   nat_ipfix_enable_disable_reply)                               \
115 _(NAT44_USER_DETAILS, nat44_user_details)                       \
116 _(NAT44_USER_SESSION_DETAILS, nat44_user_session_details)       \
117 _(NAT_DET_ADD_DEL_MAP_REPLY, nat_det_add_del_map_reply)         \
118 _(NAT_DET_FORWARD_REPLY, nat_det_forward_reply)                 \
119 _(NAT_DET_REVERSE_REPLY, nat_det_reverse_reply)                 \
120 _(NAT_DET_MAP_DETAILS, nat_det_map_details)                     \
121 _(NAT_SET_TIMEOUTS_REPLY, nat_set_timeouts_reply)               \
122 _(NAT_GET_TIMEOUTS_REPLY, nat_get_timeouts_reply)               \
123 _(NAT_DET_CLOSE_SESSION_OUT_REPLY,                              \
124   nat_det_close_session_out_reply)                              \
125 _(NAT_DET_CLOSE_SESSION_IN_REPLY,                               \
126   nat_det_close_session_in_reply)                               \
127 _(NAT_DET_SESSION_DETAILS, nat_det_session_details)
128
129 static int api_nat44_add_del_address_range (vat_main_t * vam)
130 {
131   unformat_input_t * i = vam->input;
132   ip4_address_t start_addr, end_addr;
133   u32 start_host_order, end_host_order;
134   vl_api_nat44_add_del_address_range_t * mp;
135   u8 is_add = 1;
136   int count;
137   int ret;
138
139   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
140     {
141       if (unformat (i, "%U - %U",
142                     unformat_ip4_address, &start_addr,
143                     unformat_ip4_address, &end_addr))
144         ;
145       else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
146         end_addr = start_addr;
147       else if (unformat (i, "del"))
148         is_add = 0;
149       else
150         {
151           clib_warning("unknown input '%U'", format_unformat_error, i);
152           return -99;
153         }
154     }
155
156   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
157   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
158
159   if (end_host_order < start_host_order)
160     {
161       errmsg ("end address less than start address\n");
162       return -99;
163     }
164
165   count = (end_host_order - start_host_order) + 1;
166
167   if (count > 1024)
168     {
169     errmsg ("%U - %U, %d addresses...\n",
170            format_ip4_address, &start_addr,
171            format_ip4_address, &end_addr,
172            count);
173     }
174
175   M(NAT44_ADD_DEL_ADDRESS_RANGE, mp);
176
177   memcpy (mp->first_ip_address, &start_addr, 4);
178   memcpy (mp->last_ip_address, &end_addr, 4);
179   mp->is_add = is_add;
180
181   S(mp);
182   W (ret);
183   return ret;
184 }
185
186 static int api_nat44_interface_add_del_feature (vat_main_t * vam)
187 {
188   unformat_input_t * i = vam->input;
189   vl_api_nat44_interface_add_del_feature_t * mp;
190   u32 sw_if_index;
191   u8 sw_if_index_set = 0;
192   u8 is_inside = 1;
193   u8 is_add = 1;
194   int ret;
195
196   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
197     {
198       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
199         sw_if_index_set = 1;
200       else if (unformat (i, "sw_if_index %d", &sw_if_index))
201         sw_if_index_set = 1;
202       else if (unformat (i, "out"))
203         is_inside = 0;
204       else if (unformat (i, "in"))
205         is_inside = 1;
206       else if (unformat (i, "del"))
207         is_add = 0;
208       else
209         {
210           clib_warning("unknown input '%U'", format_unformat_error, i);
211           return -99;
212         }
213     }
214
215   if (sw_if_index_set == 0)
216     {
217       errmsg ("interface / sw_if_index required\n");
218       return -99;
219     }
220
221   M(NAT44_INTERFACE_ADD_DEL_FEATURE, mp);
222   mp->sw_if_index = ntohl(sw_if_index);
223   mp->is_add = is_add;
224   if (is_inside)
225     mp->flags |= NAT_API_IS_INSIDE;
226
227   S(mp);
228   W (ret);
229   return ret;
230 }
231
232 static int api_nat44_add_del_static_mapping(vat_main_t * vam)
233 {
234   unformat_input_t * i = vam->input;
235   vl_api_nat44_add_del_static_mapping_t * mp;
236   u8 external_addr_set = 0;
237   u8 local_addr_set = 0;
238   u8 is_add = 1;
239   u8 addr_only = 1;
240   ip4_address_t local_addr, external_addr;
241   u32 local_port = 0, external_port = 0, vrf_id = ~0;
242   u32 sw_if_index = ~0;
243   u8 sw_if_index_set = 0;
244   u32 proto = ~0;
245   u8 proto_set = 0;
246   int ret;
247
248   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
249     {
250       if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr))
251         local_addr_set = 1;
252       else if (unformat (i, "external_addr %U", unformat_ip4_address,
253                          &external_addr))
254         external_addr_set = 1;
255       else if (unformat (i, "local_port %u", &local_port))
256         addr_only = 0;
257       else if (unformat (i, "external_port %u", &external_port))
258         addr_only = 0;
259       else if (unformat (i, "external_if %U", unformat_sw_if_index, vam,
260                          &sw_if_index))
261         sw_if_index_set = 1;
262       else if (unformat (i, "external_sw_if_index %d", &sw_if_index))
263         sw_if_index_set = 1;
264       else if (unformat (i, "vrf %u", &vrf_id))
265         ;
266       else if (unformat (i, "protocol %u", &proto))
267         proto_set = 1;
268       else if (unformat (i, "del"))
269         is_add = 0;
270       else
271         {
272           clib_warning("unknown input '%U'", format_unformat_error, i);
273           return -99;
274         }
275     }
276
277   if (!addr_only && !proto_set)
278     {
279       errmsg ("protocol required\n");
280       return -99;
281     }
282
283   if (!local_addr_set)
284     {
285       errmsg ("local addr required\n");
286       return -99;
287     }
288   if (!external_addr_set && !sw_if_index_set)
289     {
290       errmsg ("external addr or interface required\n");
291       return -99;
292     }
293
294   M(NAT44_ADD_DEL_STATIC_MAPPING, mp);
295
296   mp->is_add = is_add;
297   if (addr_only)
298     mp->flags |= NAT_API_IS_ADDR_ONLY;
299
300   mp->local_port = ntohs ((u16) local_port);
301   mp->external_port = ntohs ((u16) external_port);
302   mp->external_sw_if_index = ntohl (sw_if_index);
303   mp->vrf_id = ntohl (vrf_id);
304   mp->protocol = (u8) proto;
305   memcpy (mp->local_ip_address, &local_addr, 4);
306   memcpy (mp->external_ip_address, &external_addr, 4);
307
308   S(mp);
309   W (ret);
310   return ret;
311 }
312
313 static void vl_api_nat_control_ping_reply_t_handler
314   (vl_api_nat_control_ping_reply_t * mp)
315 {
316   vat_main_t *vam = &vat_main;
317   i32 retval = ntohl (mp->retval);
318   if (vam->async_mode)
319     {
320       vam->async_errors += (retval < 0);
321     }
322   else
323     {
324       vam->retval = retval;
325       vam->result_ready = 1;
326     }
327 }
328
329 static void vl_api_nat44_static_mapping_details_t_handler
330   (vl_api_nat44_static_mapping_details_t *mp)
331 {
332   snat_test_main_t * sm = &snat_test_main;
333   vat_main_t *vam = sm->vat_main;
334   nat_config_flags_t flags = (nat_config_flags_t) mp->flags;
335
336   if (flags & NAT_API_IS_ADDR_ONLY && mp->external_sw_if_index != ~0)
337       fformat (vam->ofp, "%15U%6s%15d%6s%11d%6d\n",
338                format_ip4_address, &mp->local_ip_address, "",
339                ntohl (mp->external_sw_if_index), "",
340                ntohl (mp->vrf_id),
341                mp->protocol);
342   else if (flags & NAT_API_IS_ADDR_ONLY && mp->external_sw_if_index == ~0)
343       fformat (vam->ofp, "%15U%6s%15U%6s%11d%6d\n",
344                format_ip4_address, &mp->local_ip_address, "",
345                format_ip4_address, &mp->external_ip_address, "",
346                ntohl (mp->vrf_id),
347                mp->protocol);
348   else if (!(flags & NAT_API_IS_ADDR_ONLY) && mp->external_sw_if_index != ~0)
349       fformat (vam->ofp, "%15U%6d%15d%6d%11d%6d\n",
350                format_ip4_address, &mp->local_ip_address,
351                ntohs (mp->local_port),
352                ntohl (mp->external_sw_if_index),
353                ntohs (mp->external_port),
354                ntohl (mp->vrf_id),
355                mp->protocol);
356   else
357       fformat (vam->ofp, "%15U%6d%15U%6d%11d%6d\n",
358                format_ip4_address, &mp->local_ip_address,
359                ntohs (mp->local_port),
360                format_ip4_address, &mp->external_ip_address,
361                ntohs (mp->external_port),
362                ntohl (mp->vrf_id),
363                mp->protocol);
364
365 }
366
367 static int api_nat44_static_mapping_dump(vat_main_t * vam)
368 {
369   vl_api_nat44_static_mapping_dump_t * mp;
370   vl_api_nat_control_ping_t *mp_ping;
371   int ret;
372
373   if (vam->json_output)
374     {
375       clib_warning ("JSON output not supported for nat44_static_mapping_dump");
376       return -99;
377     }
378
379   fformat (vam->ofp, "%21s%21s\n", "local", "external");
380   fformat (vam->ofp, "%15s%6s%15s%6s%11s%6s\n", "address", "port",
381            "address/if_idx", "port", "vrf", "proto");
382
383   M(NAT44_STATIC_MAPPING_DUMP, mp);
384   S(mp);
385
386   /* Use a control ping for synchronization */
387   M(NAT_CONTROL_PING, mp_ping);
388   S(mp_ping);
389
390   W (ret);
391   return ret;
392 }
393
394 static void vl_api_nat_show_config_reply_t_handler
395   (vl_api_nat_show_config_reply_t *mp)
396 {
397   snat_test_main_t * sm = &snat_test_main;
398   vat_main_t *vam = sm->vat_main;
399   i32 retval = ntohl (mp->retval);
400
401   if (retval >= 0)
402     {
403       fformat (vam->ofp, "translation hash buckets %d\n",
404                ntohl (mp->translation_buckets));
405       fformat (vam->ofp, "translation hash memory %d\n",
406                ntohl (mp->translation_memory_size));
407       fformat (vam->ofp, "user hash buckets %d\n", ntohl (mp->user_buckets));
408       fformat (vam->ofp, "user hash memory %d\n", ntohl (mp->user_memory_size));
409       fformat (vam->ofp, "max translations per user %d\n",
410                ntohl (mp->max_translations_per_user));
411       fformat (vam->ofp, "outside VRF id %d\n", ntohl (mp->outside_vrf_id));
412       fformat (vam->ofp, "inside VRF id %d\n", ntohl (mp->inside_vrf_id));
413       if (mp->static_mapping_only)
414         {
415           fformat (vam->ofp, "static mapping only");
416           if (mp->static_mapping_connection_tracking)
417             fformat (vam->ofp, " connection tracking");
418           fformat (vam->ofp, "\n");
419         }
420     }
421   vam->retval = retval;
422   vam->result_ready = 1;
423 }
424
425 static int api_nat_show_config(vat_main_t * vam)
426 {
427   vl_api_nat_show_config_t * mp;
428   int ret;
429
430   if (vam->json_output)
431     {
432       clib_warning ("JSON output not supported for nat_show_config");
433       return -99;
434     }
435
436   M(NAT_SHOW_CONFIG, mp);
437   S(mp);
438   W (ret);
439   return ret;
440 }
441
442 static void vl_api_nat44_address_details_t_handler
443   (vl_api_nat44_address_details_t *mp)
444 {
445   snat_test_main_t * sm = &snat_test_main;
446   vat_main_t *vam = sm->vat_main;
447
448   fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address);
449 }
450
451 static int api_nat44_address_dump(vat_main_t * vam)
452 {
453   vl_api_nat44_address_dump_t * mp;
454   vl_api_nat_control_ping_t *mp_ping;
455   int ret;
456
457   if (vam->json_output)
458     {
459       clib_warning ("JSON output not supported for nat44_address_dump");
460       return -99;
461     }
462
463   M(NAT44_ADDRESS_DUMP, mp);
464   S(mp);
465
466   /* Use a control ping for synchronization */
467   M(NAT_CONTROL_PING, mp_ping);
468   S(mp_ping);
469
470   W (ret);
471   return ret;
472 }
473
474 static void vl_api_nat44_interface_details_t_handler
475   (vl_api_nat44_interface_details_t *mp)
476 {
477   nat_config_flags_t flags = (nat_config_flags_t) mp->flags;
478   snat_test_main_t * sm = &snat_test_main;
479   vat_main_t *vam = sm->vat_main;
480
481   if ((flags & NAT_API_IS_INSIDE) && (flags & NAT_API_IS_OUTSIDE))
482     {
483       fformat (vam->ofp, "sw_if_index %d in & out\n", ntohl (mp->sw_if_index));
484     }
485   else
486     {
487       fformat (vam->ofp, "sw_if_index %d %s\n", ntohl (mp->sw_if_index),
488                flags & NAT_API_IS_INSIDE ? "in" : "out");
489     }
490 }
491
492 static int api_nat44_interface_dump(vat_main_t * vam)
493 {
494   vl_api_nat44_interface_dump_t * mp;
495   vl_api_nat_control_ping_t *mp_ping;
496   int ret;
497
498   if (vam->json_output)
499     {
500       clib_warning ("JSON output not supported for nat44_address_dump");
501       return -99;
502     }
503
504   M(NAT44_INTERFACE_DUMP, mp);
505   S(mp);
506
507   /* Use a control ping for synchronization */
508   M(NAT_CONTROL_PING, mp_ping);
509   S(mp_ping);
510
511   W (ret);
512   return ret;
513 }
514
515 static int api_nat_set_workers (vat_main_t * vam)
516 {
517   unformat_input_t * i = vam->input;
518   vl_api_nat_set_workers_t * mp;
519   uword *bitmap;
520   int ret;
521
522   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
523     {
524       if (unformat (i, "%U", unformat_bitmap_list, &bitmap))
525         ;
526       else
527         {
528           clib_warning("unknown input '%U'", format_unformat_error, i);
529           return -99;
530         }
531     }
532
533   M(NAT_SET_WORKERS, mp);
534   mp->worker_mask = clib_host_to_net_u64 (bitmap[0]);
535
536   S(mp);
537   W (ret);
538   return ret;
539 }
540
541 static void vl_api_nat_worker_details_t_handler
542   (vl_api_nat_worker_details_t *mp)
543 {
544   snat_test_main_t * sm = &snat_test_main;
545   vat_main_t *vam = sm->vat_main;
546
547   fformat (vam->ofp, "worker_index %d (%s at lcore %u)\n",
548            ntohl (mp->worker_index), mp->name, ntohl (mp->lcore_id));
549 }
550
551 static int api_nat_worker_dump(vat_main_t * vam)
552 {
553   vl_api_nat_worker_dump_t * mp;
554   vl_api_nat_control_ping_t *mp_ping;
555   int ret;
556
557   if (vam->json_output)
558     {
559       clib_warning ("JSON output not supported for nat_address_dump");
560       return -99;
561     }
562
563   M(NAT_WORKER_DUMP, mp);
564   S(mp);
565
566   /* Use a control ping for synchronization */
567   M(NAT_CONTROL_PING, mp_ping);
568   S(mp_ping);
569
570   W (ret);
571   return ret;
572 }
573
574 static int api_nat44_add_del_interface_addr (vat_main_t * vam)
575 {
576   unformat_input_t * i = vam->input;
577   vl_api_nat44_add_del_interface_addr_t * mp;
578   u32 sw_if_index;
579   u8 sw_if_index_set = 0;
580   u8 is_add = 1;
581   int ret;
582
583   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
584     {
585       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
586         sw_if_index_set = 1;
587       else if (unformat (i, "sw_if_index %d", &sw_if_index))
588         sw_if_index_set = 1;
589       else if (unformat (i, "del"))
590         is_add = 0;
591       else
592         {
593           clib_warning("unknown input '%U'", format_unformat_error, i);
594           return -99;
595         }
596     }
597
598   if (sw_if_index_set == 0)
599     {
600       errmsg ("interface / sw_if_index required\n");
601       return -99;
602     }
603
604   M(NAT44_ADD_DEL_INTERFACE_ADDR, mp);
605   mp->sw_if_index = ntohl(sw_if_index);
606
607   mp->is_add = is_add;
608
609   S(mp);
610   W (ret);
611   return ret;
612 }
613
614 static void vl_api_nat44_interface_addr_details_t_handler
615   (vl_api_nat44_interface_addr_details_t *mp)
616 {
617   snat_test_main_t * sm = &snat_test_main;
618   vat_main_t *vam = sm->vat_main;
619
620   fformat (vam->ofp, "sw_if_index %d\n", ntohl (mp->sw_if_index));
621 }
622
623 static int api_nat44_interface_addr_dump(vat_main_t * vam)
624 {
625   vl_api_nat44_interface_addr_dump_t * mp;
626   vl_api_nat_control_ping_t *mp_ping;
627   int ret;
628
629   if (vam->json_output)
630     {
631       clib_warning ("JSON output not supported for nat44_address_dump");
632       return -99;
633     }
634
635   M(NAT44_INTERFACE_ADDR_DUMP, mp);
636   S(mp);
637
638   /* Use a control ping for synchronization */
639   M(NAT_CONTROL_PING, mp_ping);
640   S(mp_ping);
641
642   W (ret);
643   return ret;
644 }
645
646 static int api_nat_ipfix_enable_disable (vat_main_t * vam)
647 {
648   unformat_input_t * i = vam->input;
649   vl_api_nat_ipfix_enable_disable_t * mp;
650   u32 domain_id = 0;
651   u32 src_port = 0;
652   u8 enable = 1;
653   int ret;
654
655   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
656     {
657       if (unformat (i, "domain %d", &domain_id))
658         ;
659       else if (unformat (i, "src_port %d", &src_port))
660         ;
661       else if (unformat (i, "disable"))
662         enable = 0;
663       else
664         {
665           clib_warning("unknown input '%U'", format_unformat_error, i);
666           return -99;
667         }
668     }
669
670   M(NAT_IPFIX_ENABLE_DISABLE, mp);
671   mp->domain_id = htonl(domain_id);
672   mp->src_port = htons((u16) src_port);
673   mp->enable = enable;
674
675   S(mp);
676   W (ret);
677   return ret;
678 }
679
680 static void vl_api_nat44_user_session_details_t_handler
681   (vl_api_nat44_user_session_details_t *mp)
682 {
683   snat_test_main_t * sm = &snat_test_main;
684   vat_main_t *vam = sm->vat_main;
685
686   fformat(vam->ofp, "%s session %U:%d to %U:%d protocol id %d "
687                     "total packets %d total bytes %lld\n",
688           mp->flags & NAT_API_IS_STATIC ? "static" : "dynamic",
689           format_ip4_address, mp->inside_ip_address, ntohs(mp->inside_port),
690           format_ip4_address, mp->outside_ip_address, ntohs(mp->outside_port),
691           ntohs(mp->protocol), ntohl(mp->total_pkts),
692           clib_net_to_host_u64(mp->total_bytes));
693 }
694
695 static int api_nat44_user_session_dump(vat_main_t * vam)
696 {
697   unformat_input_t* i = vam->input;
698   vl_api_nat44_user_session_dump_t * mp;
699   vl_api_nat_control_ping_t *mp_ping;
700   ip4_address_t addr;
701   u32 vrf_id = ~0;
702   int ret;
703
704   if (vam->json_output)
705     {
706       clib_warning ("JSON output not supported for nat44_address_dump");
707       return -99;
708     }
709
710   if (unformat (i, "ip_address %U vrf_id %d",
711                 unformat_ip4_address, &addr, &vrf_id))
712     ;
713   else
714     {
715       clib_warning("unknown input '%U'", format_unformat_error, i);
716       return -99;
717     }
718
719   M(NAT44_USER_SESSION_DUMP, mp);
720   S(mp);
721
722   /* Use a control ping for synchronization */
723   M(NAT_CONTROL_PING, mp_ping);
724   clib_memset(mp->ip_address, 0, 16);
725   clib_memcpy(mp->ip_address, &addr, 4);
726   mp->vrf_id = htonl(vrf_id);
727   S(mp_ping);
728
729   W (ret);
730   return ret;
731 }
732
733 static void vl_api_nat44_user_details_t_handler
734   (vl_api_nat44_user_details_t *mp)
735 {
736   snat_test_main_t * sm = &snat_test_main;
737   vat_main_t *vam = sm->vat_main;
738
739   fformat(vam->ofp, "user with ip %U with vrf_id %d "
740                     "with %d sessions and %d static sessions\n",
741           format_ip4_address, mp->ip_address, ntohl(mp->vrf_id),
742           ntohl(mp->nsessions), ntohl(mp->nstaticsessions));
743 }
744
745 static int api_nat44_user_dump(vat_main_t * vam)
746 {
747   vl_api_nat44_user_dump_t * mp;
748   vl_api_nat_control_ping_t *mp_ping;
749   int ret;
750
751   if (vam->json_output)
752     {
753       clib_warning ("JSON output not supported for nat44_address_dump");
754       return -99;
755     }
756
757   M(NAT44_USER_DUMP, mp);
758   S(mp);
759
760   /* Use a control ping for synchronization */
761   M(NAT_CONTROL_PING, mp_ping);
762   S(mp_ping);
763
764   W (ret);
765   return ret;
766 }
767
768 static int api_nat_det_add_del_map (vat_main_t * vam)
769 {
770   unformat_input_t * i = vam->input;
771   vl_api_nat_det_add_del_map_t * mp;
772   ip4_address_t in_addr, out_addr;
773   u32 in_plen, out_plen;
774   u8 is_add = 1;
775   int ret;
776
777   if (unformat (i, "in %U/%d out %U/%d",
778                 unformat_ip4_address, &in_addr, &in_plen,
779                 unformat_ip4_address, &out_addr, &out_plen))
780     ;
781   else if (unformat (i, "del"))
782     is_add = 0;
783   else
784     {
785       clib_warning("unknown input '%U'", format_unformat_error, i);
786       return -99;
787     }
788
789   M(NAT_DET_ADD_DEL_MAP, mp);
790   clib_memcpy(mp->in_addr, &in_addr, 4);
791   mp->in_plen = in_plen;
792   clib_memcpy(mp->out_addr, &out_addr, 4);
793   mp->out_plen = out_plen;
794   mp->is_add = is_add;
795
796   S(mp);
797   W (ret);
798   return ret;
799 }
800
801 static void vl_api_nat_det_forward_reply_t_handler
802   (vl_api_nat_det_forward_reply_t *mp)
803 {
804   snat_test_main_t * sm = &snat_test_main;
805   vat_main_t *vam = sm->vat_main;
806   i32 retval = ntohl(mp->retval);
807
808   if (retval >= 0)
809   {
810     fformat (vam->ofp, "outside address %U", format_ip4_address, &mp->out_addr);
811     fformat (vam->ofp, " outside port range start %d", ntohs(mp->out_port_lo));
812     fformat (vam->ofp, " outside port range end %d\n", ntohs(mp->out_port_hi));
813   }
814
815   vam->retval = retval;
816   vam->result_ready = 1;
817 }
818
819 static int api_nat_det_forward (vat_main_t * vam)
820 {
821   unformat_input_t * i = vam->input;
822   vl_api_nat_det_forward_t * mp;
823   ip4_address_t in_addr;
824   int ret;
825
826   if (unformat (i, "%U", unformat_ip4_address, &in_addr))
827     ;
828   else
829     {
830       clib_warning("unknown input '%U'", format_unformat_error, i);
831       return -99;
832     }
833
834   M(NAT_DET_FORWARD, mp);
835   clib_memcpy(mp->in_addr, &in_addr, 4);
836
837   S(mp);
838   W(ret);
839   return ret;
840 }
841
842 static void vl_api_nat_det_reverse_reply_t_handler
843   (vl_api_nat_det_reverse_reply_t *mp)
844 {
845   snat_test_main_t * sm = &snat_test_main;
846   vat_main_t *vam = sm->vat_main;
847   i32 retval = ntohl(mp->retval);
848
849   if (retval >= 0)
850   {
851     fformat (vam->ofp, "inside address %U\n", format_ip4_address, &mp->in_addr);
852   }
853
854   vam->retval = retval;
855   vam->result_ready = 1;
856 }
857
858 static int api_nat_det_reverse (vat_main_t * vam)
859 {
860   unformat_input_t * i = vam->input;
861   vl_api_nat_det_reverse_t * mp;
862   ip4_address_t out_addr;
863   u32 out_port;
864   int ret;
865
866   if (unformat (i, "%U %d", unformat_ip4_address, &out_addr, &out_port))
867     ;
868   else
869     {
870       clib_warning("unknown input '%U'", format_unformat_error, i);
871       return -99;
872     }
873
874   M(NAT_DET_REVERSE, mp);
875   clib_memcpy(mp->out_addr, &out_addr, 4);
876   mp->out_port = htons((u16)out_port);
877
878   S(mp);
879   W(ret);
880   return ret;
881 }
882
883 static void vl_api_nat_det_map_details_t_handler
884   (vl_api_nat_det_map_details_t *mp)
885 {
886   snat_test_main_t * sm = &snat_test_main;
887   vat_main_t *vam = sm->vat_main;
888
889   fformat (vam->ofp, "Deterministic S-NAT mapping in %U/%d out %U/%d "
890                      "ports per host %d sharing ratio %d "
891                      "number of sessions %d",
892            format_ip4_address, mp->in_addr, mp->in_plen,
893            format_ip4_address, mp->out_addr, mp->out_plen,
894            ntohs(mp->ports_per_host), ntohl(mp->sharing_ratio),
895            ntohl(mp->ses_num));
896 }
897
898 static int api_nat_det_map_dump(vat_main_t * vam)
899 {
900   vl_api_nat_det_map_dump_t * mp;
901   vl_api_nat_control_ping_t *mp_ping;
902   int ret;
903
904   if (vam->json_output)
905     {
906       clib_warning ("JSON output not supported for nat_det_map_dump");
907       return -99;
908     }
909
910   M(NAT_DET_MAP_DUMP, mp);
911   S(mp);
912
913   /* Use a control ping for synchronization */
914   M(NAT_CONTROL_PING, mp_ping);
915   S(mp_ping);
916
917   W (ret);
918   return ret;
919 }
920
921 static int api_nat_set_timeouts (vat_main_t * vam)
922 {
923   unformat_input_t * i = vam->input;
924   vl_api_nat_set_timeouts_t * mp;
925   u32 udp = SNAT_UDP_TIMEOUT;
926   u32 tcp_established = SNAT_TCP_ESTABLISHED_TIMEOUT;
927   u32 tcp_transitory = SNAT_TCP_TRANSITORY_TIMEOUT;
928   u32 icmp = SNAT_ICMP_TIMEOUT;
929   int ret;
930
931   if (unformat (i, "udp %d", &udp))
932     ;
933   else if (unformat (i, "tcp_established %d", &tcp_established))
934     ;
935   else if (unformat (i, "tcp_transitory %d", &tcp_transitory))
936     ;
937   else if (unformat (i, "icmp %d", &icmp))
938     ;
939   else
940     {
941       clib_warning("unknown input '%U'", format_unformat_error, i);
942       return -99;
943     }
944
945   M(NAT_SET_TIMEOUTS, mp);
946   mp->udp = htonl(udp);
947   mp->tcp_established = htonl(tcp_established);
948   mp->tcp_transitory = htonl(tcp_transitory);
949   mp->icmp = htonl(icmp);
950
951   S(mp);
952   W (ret);
953   return ret;
954 }
955
956 static void vl_api_nat_get_timeouts_reply_t_handler
957   (vl_api_nat_get_timeouts_reply_t *mp)
958 {
959   snat_test_main_t * sm = &snat_test_main;
960   vat_main_t *vam = sm->vat_main;
961   i32 retval = ntohl (mp->retval);
962
963   if (retval >= 0)
964     {
965       fformat (vam->ofp, "udp timeout: %dsec\n", ntohl (mp->udp));
966       fformat (vam->ofp, "tcp-established timeout: %dsec",
967                ntohl (mp->tcp_established));
968       fformat (vam->ofp, "tcp-transitory timeout: %dsec",
969                ntohl (mp->tcp_transitory));
970       fformat (vam->ofp, "icmp timeout: %dsec", ntohl (mp->icmp));
971     }
972   vam->retval = retval;
973   vam->result_ready = 1;
974 }
975
976 static int api_nat_get_timeouts(vat_main_t * vam)
977 {
978   vl_api_nat_get_timeouts_t * mp;
979   int ret;
980
981   if (vam->json_output)
982     {
983       clib_warning ("JSON output not supported for nat_get_timeouts");
984       return -99;
985     }
986
987   M(NAT_GET_TIMEOUTS, mp);
988   S(mp);
989   W (ret);
990   return ret;
991 }
992
993 static int api_nat_det_close_session_out (vat_main_t * vam)
994 {
995   unformat_input_t * i = vam->input;
996   vl_api_nat_det_close_session_out_t * mp;
997   ip4_address_t out_addr, ext_addr;
998   u32 out_port, ext_port;
999   int ret;
1000
1001   if (unformat (i, "%U:%d %U:%d",
1002                 unformat_ip4_address, &out_addr, &out_port,
1003                 unformat_ip4_address, &ext_addr, &ext_port))
1004     ;
1005   else
1006     {
1007       clib_warning("unknown input '%U'", format_unformat_error, i);
1008       return -99;
1009     }
1010
1011   M(NAT_DET_CLOSE_SESSION_OUT, mp);
1012   clib_memcpy(mp->out_addr, &out_addr, 4);
1013   mp->out_port = ntohs((u16)out_port);
1014   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1015   mp->ext_port = ntohs((u16)ext_port);
1016
1017   S(mp);
1018   W (ret);
1019   return ret;
1020 }
1021
1022 static int api_nat_det_close_session_in (vat_main_t * vam)
1023 {
1024   unformat_input_t * i = vam->input;
1025   vl_api_nat_det_close_session_in_t * mp;
1026   ip4_address_t in_addr, ext_addr;
1027   u32 in_port, ext_port;
1028   int ret;
1029
1030   if (unformat (i, "%U:%d %U:%d",
1031                 unformat_ip4_address, &in_addr, &in_port,
1032                 unformat_ip4_address, &ext_addr, &ext_port))
1033     ;
1034   else
1035     {
1036       clib_warning("unknown input '%U'", format_unformat_error, i);
1037       return -99;
1038     }
1039
1040   M(NAT_DET_CLOSE_SESSION_IN, mp);
1041   clib_memcpy(mp->in_addr, &in_addr, 4);
1042   mp->in_port = ntohs((u16)in_port);
1043   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1044   mp->ext_port = ntohs((u16)ext_port);
1045
1046   S(mp);
1047   W (ret);
1048   return ret;
1049 }
1050
1051 static void vl_api_nat_det_session_details_t_handler
1052   (vl_api_nat_det_session_details_t *mp)
1053 {
1054   snat_test_main_t * sm = &snat_test_main;
1055   vat_main_t *vam = sm->vat_main;
1056
1057   fformat(vam->ofp, "deterministic session, external host address %U, "
1058                     "external host port %d, outer port %d, inside port %d",
1059           format_ip4_address, mp->ext_addr, mp->ext_port,
1060           mp->out_port, mp->in_port);
1061 }
1062
1063 static int api_nat_det_session_dump(vat_main_t * vam)
1064 {
1065   unformat_input_t* i = vam->input;
1066   vl_api_nat_det_session_dump_t * mp;
1067   vl_api_nat_control_ping_t *mp_ping;
1068   ip4_address_t user_addr;
1069   int ret;
1070
1071   if (vam->json_output)
1072     {
1073       clib_warning ("JSON output not supported for nat_det_session_dump");
1074       return -99;
1075     }
1076
1077   if (unformat (i, "user_addr %U", unformat_ip4_address, &user_addr))
1078     ;
1079   else
1080     {
1081       clib_warning ("unknown input '%U'", format_unformat_error, i);
1082       return -99;
1083     }
1084
1085   M(NAT_DET_SESSION_DUMP, mp);
1086   clib_memcpy (&mp->user_addr, &user_addr, 4);
1087   S(mp);
1088
1089   /* Use a control ping for synchronization */
1090   M(NAT_CONTROL_PING, mp_ping);
1091   S(mp_ping);
1092
1093   W (ret);
1094   return ret;
1095 }
1096
1097 /*
1098  * List of messages that the api test plugin sends,
1099  * and that the data plane plugin processes
1100  */
1101 #define foreach_vpe_api_msg                                       \
1102 _(nat44_add_del_address_range, "<start-addr> [- <end-addr] [del]")\
1103 _(nat44_interface_add_del_feature,                                \
1104   "<intfc> | sw_if_index <id> [in] [out] [del]")                  \
1105 _(nat44_add_del_static_mapping, "local_addr <ip>"                 \
1106   " (external_addr <ip> | external_if <intfc> |"                  \
1107   " external_sw_if_ndex <id>) [local_port <n>]"                   \
1108   " [external_port <n>] [vrf <table-id>] [del] protocol <n>")     \
1109 _(nat_set_workers, "<wokrers_bitmap>")                            \
1110 _(nat44_static_mapping_dump, "")                                  \
1111 _(nat_show_config, "")                                            \
1112 _(nat44_address_dump, "")                                         \
1113 _(nat44_interface_dump, "")                                       \
1114 _(nat_worker_dump, "")                                            \
1115 _(nat44_add_del_interface_addr,                                   \
1116   "<intfc> | sw_if_index <id> [del]")                             \
1117 _(nat44_interface_addr_dump, "")                                  \
1118 _(nat_ipfix_enable_disable, "[domain <id>] [src_port <n>] "       \
1119   "[disable]")                                                    \
1120 _(nat44_user_dump, "")                                            \
1121 _(nat44_user_session_dump, "ip_address <ip> vrf_id <table-id>")   \
1122 _(nat_det_add_del_map, "in <in_addr>/<in_plen> out "              \
1123   "<out_addr>/<out_plen> [del]")                                  \
1124 _(nat_det_forward, "<in_addr>")                                   \
1125 _(nat_det_reverse, "<out_addr> <out_port>")                       \
1126 _(nat_det_map_dump, "")                                           \
1127 _(nat_set_timeouts, "[udp <sec> | tcp_established <sec> | "       \
1128   "tcp_transitory <sec> | icmp <sec>]")                           \
1129 _(nat_get_timeouts, "")                                           \
1130 _(nat_det_close_session_out, "<out_addr>:<out_port> "             \
1131   "<ext_addr>:<ext_port>")                                        \
1132 _(nat_det_close_session_in, "<in_addr>:<in_port> "                \
1133   "<out_addr>:<out_port>")                                        \
1134 _(nat_det_session_dump, "ip_address <user_addr>")
1135
1136 static void
1137 snat_vat_api_hookup (vat_main_t *vam)
1138 {
1139   snat_test_main_t * sm __attribute__((unused)) = &snat_test_main;
1140   /* Hook up handlers for replies from the data plane plug-in */
1141 #define _(N,n)                                                  \
1142   vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),       \
1143                           #n,                                   \
1144                           vl_api_##n##_t_handler,               \
1145                           vl_noop_handler,                      \
1146                           vl_api_##n##_t_endian,                \
1147                           vl_api_##n##_t_print,                 \
1148                           sizeof(vl_api_##n##_t), 1);
1149   foreach_vpe_api_reply_msg;
1150 #undef _
1151
1152   /* API messages we can send */
1153 #define _(n,h)                                          \
1154   hash_set_mem (vam->function_by_name, #n, api_##n);
1155   foreach_vpe_api_msg;
1156 #undef _
1157
1158   /* Help strings */
1159 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
1160   foreach_vpe_api_msg;
1161 #undef _
1162 }
1163
1164 clib_error_t * vat_plugin_register (vat_main_t *vam)
1165 {
1166   snat_test_main_t * sm = &snat_test_main;
1167   u8 * name;
1168
1169   sm->vat_main = vam;
1170
1171   /* Ask the vpp engine for the first assigned message-id */
1172   name = format (0, "nat_%08x%c", api_version, 0);
1173   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
1174
1175   if (sm->msg_id_base != (u16) ~0)
1176     snat_vat_api_hookup (vam);
1177
1178   vec_free(name);
1179
1180   return 0;
1181 }