Memory overwritten when using unformat %u (VPP-987)
[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 #include <vlibsocket/api.h>
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 _(snat_add_address_range_reply)                 \
66 _(snat_interface_add_del_feature_reply)         \
67 _(snat_add_static_mapping_reply)                \
68 _(snat_set_workers_reply)                       \
69 _(snat_add_del_interface_addr_reply)            \
70 _(snat_ipfix_enable_disable_reply)              \
71 _(snat_add_det_map_reply)                       \
72 _(snat_det_set_timeouts_reply)                  \
73 _(snat_det_close_session_out_reply)             \
74 _(snat_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 _(SNAT_ADD_ADDRESS_RANGE_REPLY, snat_add_address_range_reply)   \
98 _(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY,                         \
99   snat_interface_add_del_feature_reply)                         \
100 _(SNAT_ADD_STATIC_MAPPING_REPLY, snat_add_static_mapping_reply) \
101 _(SNAT_CONTROL_PING_REPLY, snat_control_ping_reply)             \
102 _(SNAT_STATIC_MAPPING_DETAILS, snat_static_mapping_details)     \
103 _(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply)               \
104 _(SNAT_ADDRESS_DETAILS, snat_address_details)                   \
105 _(SNAT_INTERFACE_DETAILS, snat_interface_details)               \
106 _(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply)               \
107 _(SNAT_WORKER_DETAILS, snat_worker_details)                     \
108 _(SNAT_ADD_DEL_INTERFACE_ADDR_REPLY,                            \
109   snat_add_del_interface_addr_reply)                            \
110 _(SNAT_INTERFACE_ADDR_DETAILS, snat_interface_addr_details)     \
111 _(SNAT_IPFIX_ENABLE_DISABLE_REPLY,                              \
112   snat_ipfix_enable_disable_reply)                              \
113 _(SNAT_USER_DETAILS, snat_user_details)                         \
114 _(SNAT_USER_SESSION_DETAILS, snat_user_session_details)         \
115 _(SNAT_ADD_DET_MAP_REPLY, snat_add_det_map_reply)               \
116 _(SNAT_DET_FORWARD_REPLY, snat_det_forward_reply)               \
117 _(SNAT_DET_REVERSE_REPLY, snat_det_reverse_reply)               \
118 _(SNAT_DET_MAP_DETAILS, snat_det_map_details)                   \
119 _(SNAT_DET_SET_TIMEOUTS_REPLY, snat_det_set_timeouts_reply)     \
120 _(SNAT_DET_GET_TIMEOUTS_REPLY, snat_det_get_timeouts_reply)     \
121 _(SNAT_DET_CLOSE_SESSION_OUT_REPLY,                             \
122   snat_det_close_session_out_reply)                             \
123 _(SNAT_DET_CLOSE_SESSION_IN_REPLY,                              \
124   snat_det_close_session_in_reply)                              \
125 _(SNAT_DET_SESSION_DETAILS, snat_det_session_details)
126
127 static int api_snat_add_address_range (vat_main_t * vam)
128 {
129   unformat_input_t * i = vam->input;
130   ip4_address_t start_addr, end_addr;
131   u32 start_host_order, end_host_order;
132   vl_api_snat_add_address_range_t * mp;
133   u8 is_add = 1;
134   int count;
135   int ret;
136
137   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
138     {
139       if (unformat (i, "%U - %U",
140                     unformat_ip4_address, &start_addr,
141                     unformat_ip4_address, &end_addr))
142         ;
143       else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
144         end_addr = start_addr;
145       else if (unformat (i, "del"))
146         is_add = 0;
147       else
148         {
149           clib_warning("unknown input '%U'", format_unformat_error, i);
150           return -99;
151         }
152     }
153
154   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
155   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
156   
157   if (end_host_order < start_host_order)
158     {
159       errmsg ("end address less than start address\n");
160       return -99;
161     }
162
163   count = (end_host_order - start_host_order) + 1;
164
165   if (count > 1024)
166     {
167     errmsg ("%U - %U, %d addresses...\n",
168            format_ip4_address, &start_addr,
169            format_ip4_address, &end_addr,
170            count);
171     }
172   
173   M(SNAT_ADD_ADDRESS_RANGE, mp);
174
175   memcpy (mp->first_ip_address, &start_addr, 4);
176   memcpy (mp->last_ip_address, &end_addr, 4);
177   mp->is_ip4 = 1;
178   mp->is_add = is_add;
179
180   S(mp);
181   W (ret);
182   return ret;
183 }
184
185 static int api_snat_interface_add_del_feature (vat_main_t * vam)
186 {
187   unformat_input_t * i = vam->input;
188   vl_api_snat_interface_add_del_feature_t * mp;
189   u32 sw_if_index;
190   u8 sw_if_index_set = 0;
191   u8 is_inside = 1; 
192   u8 is_add = 1;
193   int ret;
194
195   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
196     {
197       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
198         sw_if_index_set = 1;
199       else if (unformat (i, "sw_if_index %d", &sw_if_index))
200         sw_if_index_set = 1;
201       else if (unformat (i, "out"))
202         is_inside = 0;
203       else if (unformat (i, "in"))
204         is_inside = 1;
205       else if (unformat (i, "del"))
206         is_add = 0;
207       else
208         {
209           clib_warning("unknown input '%U'", format_unformat_error, i);
210           return -99;
211         }
212     }
213
214   if (sw_if_index_set == 0)
215     {
216       errmsg ("interface / sw_if_index required\n");
217       return -99;
218     }
219
220   M(SNAT_INTERFACE_ADD_DEL_FEATURE, mp);
221   mp->sw_if_index = ntohl(sw_if_index);
222   mp->is_add = is_add;
223   mp->is_inside = is_inside;
224   
225   S(mp);
226   W (ret);
227   return ret;
228 }
229
230 static int api_snat_add_static_mapping(vat_main_t * vam)
231 {
232   unformat_input_t * i = vam->input;
233   vl_api_snat_add_static_mapping_t * mp;
234   u8 external_addr_set = 0;
235   u8 local_addr_set = 0;
236   u8 is_add = 1;
237   u8 addr_only = 1;
238   ip4_address_t local_addr, external_addr;
239   u32 local_port = 0, external_port = 0, vrf_id = ~0;
240   u32 sw_if_index = ~0;
241   u8 sw_if_index_set = 0;
242   u32 proto = ~0;
243   u8 proto_set = 0;
244   int ret;
245
246   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
247     {
248       if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr))
249         local_addr_set = 1;
250       else if (unformat (i, "external_addr %U", unformat_ip4_address,
251                          &external_addr))
252         external_addr_set = 1;
253       else if (unformat (i, "local_port %u", &local_port))
254         addr_only = 0;
255       else if (unformat (i, "external_port %u", &external_port))
256         addr_only = 0;
257       else if (unformat (i, "external_if %U", unformat_sw_if_index, vam,
258                          &sw_if_index))
259         sw_if_index_set = 1;
260       else if (unformat (i, "external_sw_if_index %d", &sw_if_index))
261         sw_if_index_set = 1;
262       else if (unformat (i, "vrf %u", &vrf_id))
263         ;
264       else if (unformat (i, "protocol %u", &proto))
265         proto_set = 1;
266       else if (unformat (i, "del"))
267         is_add = 0;
268       else
269         {
270           clib_warning("unknown input '%U'", format_unformat_error, i);
271           return -99;
272         }
273     }
274
275   if (!addr_only && !proto_set)
276     {
277       errmsg ("protocol required\n");
278       return -99;
279     }
280
281   if (!local_addr_set)
282     {
283       errmsg ("local addr required\n");
284       return -99;
285     }
286   if (!external_addr_set && !sw_if_index_set)
287     {
288       errmsg ("external addr or interface required\n");
289       return -99;
290     }
291
292   M(SNAT_ADD_STATIC_MAPPING, mp);
293   mp->is_add = is_add;
294   mp->is_ip4 = 1;
295   mp->addr_only = addr_only;
296   mp->local_port = ntohs ((u16) local_port);
297   mp->external_port = ntohs ((u16) external_port);
298   mp->external_sw_if_index = ntohl (sw_if_index);
299   mp->vrf_id = ntohl (vrf_id);
300   mp->protocol = (u8) proto;
301   memcpy (mp->local_ip_address, &local_addr, 4);
302   memcpy (mp->external_ip_address, &external_addr, 4);
303
304   S(mp);
305   W (ret);
306   return ret;
307 }
308
309 static void vl_api_snat_control_ping_reply_t_handler
310   (vl_api_snat_control_ping_reply_t * mp)
311 {
312   vat_main_t *vam = &vat_main;
313   i32 retval = ntohl (mp->retval);
314   if (vam->async_mode)
315     {
316       vam->async_errors += (retval < 0);
317     }
318   else
319     {
320       vam->retval = retval;
321       vam->result_ready = 1;
322     }
323 }
324
325 static void vl_api_snat_static_mapping_details_t_handler
326   (vl_api_snat_static_mapping_details_t *mp)
327 {
328   snat_test_main_t * sm = &snat_test_main;
329   vat_main_t *vam = sm->vat_main;
330
331   if (mp->addr_only && mp->external_sw_if_index != ~0)
332       fformat (vam->ofp, "%15U%6s%15d%6s%11d%6d\n",
333                format_ip4_address, &mp->local_ip_address, "",
334                ntohl (mp->external_sw_if_index), "",
335                ntohl (mp->vrf_id),
336                mp->protocol);
337   else if (mp->addr_only && mp->external_sw_if_index == ~0)
338       fformat (vam->ofp, "%15U%6s%15U%6s%11d%6d\n",
339                format_ip4_address, &mp->local_ip_address, "",
340                format_ip4_address, &mp->external_ip_address, "",
341                ntohl (mp->vrf_id),
342                mp->protocol);
343   else if (!mp->addr_only && mp->external_sw_if_index != ~0)
344       fformat (vam->ofp, "%15U%6d%15d%6d%11d%6d\n",
345                format_ip4_address, &mp->local_ip_address,
346                ntohs (mp->local_port),
347                ntohl (mp->external_sw_if_index),
348                ntohs (mp->external_port),
349                ntohl (mp->vrf_id),
350                mp->protocol);
351   else
352       fformat (vam->ofp, "%15U%6d%15U%6d%11d%6d\n",
353                format_ip4_address, &mp->local_ip_address,
354                ntohs (mp->local_port),
355                format_ip4_address, &mp->external_ip_address,
356                ntohs (mp->external_port),
357                ntohl (mp->vrf_id),
358                mp->protocol);
359
360 }
361
362 static int api_snat_static_mapping_dump(vat_main_t * vam)
363 {
364   vl_api_snat_static_mapping_dump_t * mp;
365   vl_api_snat_control_ping_t *mp_ping;
366   int ret;
367
368   if (vam->json_output)
369     {
370       clib_warning ("JSON output not supported for snat_static_mapping_dump");
371       return -99;
372     }
373
374   fformat (vam->ofp, "%21s%21s\n", "local", "external");
375   fformat (vam->ofp, "%15s%6s%15s%6s%11s%6s\n", "address", "port",
376            "address/if_idx", "port", "vrf", "proto");
377
378   M(SNAT_STATIC_MAPPING_DUMP, mp);
379   S(mp);
380
381   /* Use a control ping for synchronization */
382   M(SNAT_CONTROL_PING, mp_ping);
383   S(mp_ping);
384
385   W (ret);
386   return ret;
387 }
388
389 static void vl_api_snat_show_config_reply_t_handler
390   (vl_api_snat_show_config_reply_t *mp)
391 {
392   snat_test_main_t * sm = &snat_test_main;
393   vat_main_t *vam = sm->vat_main;
394   i32 retval = ntohl (mp->retval);
395
396   if (retval >= 0)
397     {
398       fformat (vam->ofp, "translation hash buckets %d\n",
399                ntohl (mp->translation_buckets));
400       fformat (vam->ofp, "translation hash memory %d\n",
401                ntohl (mp->translation_memory_size));
402       fformat (vam->ofp, "user hash buckets %d\n", ntohl (mp->user_buckets));
403       fformat (vam->ofp, "user hash memory %d\n", ntohl (mp->user_memory_size));
404       fformat (vam->ofp, "max translations per user %d\n",
405                ntohl (mp->max_translations_per_user));
406       fformat (vam->ofp, "outside VRF id %d\n", ntohl (mp->outside_vrf_id));
407       fformat (vam->ofp, "inside VRF id %d\n", ntohl (mp->inside_vrf_id));
408       if (mp->static_mapping_only)
409         {
410           fformat (vam->ofp, "static mapping only");
411           if (mp->static_mapping_connection_tracking)
412             fformat (vam->ofp, " connection tracking");
413           fformat (vam->ofp, "\n");
414         }
415     }
416   vam->retval = retval;
417   vam->result_ready = 1;
418 }
419
420 static int api_snat_show_config(vat_main_t * vam)
421 {
422   vl_api_snat_show_config_t * mp;
423   int ret;
424
425   if (vam->json_output)
426     {
427       clib_warning ("JSON output not supported for snat_show_config");
428       return -99;
429     }
430
431   M(SNAT_SHOW_CONFIG, mp);
432   S(mp);
433   W (ret);
434   return ret;
435 }
436
437 static void vl_api_snat_address_details_t_handler
438   (vl_api_snat_address_details_t *mp)
439 {
440   snat_test_main_t * sm = &snat_test_main;
441   vat_main_t *vam = sm->vat_main;
442
443   fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address);
444 }
445
446 static int api_snat_address_dump(vat_main_t * vam)
447 {
448   vl_api_snat_address_dump_t * mp;
449   vl_api_snat_control_ping_t *mp_ping;
450   int ret;
451
452   if (vam->json_output)
453     {
454       clib_warning ("JSON output not supported for snat_address_dump");
455       return -99;
456     }
457
458   M(SNAT_ADDRESS_DUMP, mp);
459   S(mp);
460
461   /* Use a control ping for synchronization */
462   M(SNAT_CONTROL_PING, mp_ping);
463   S(mp_ping);
464
465   W (ret);
466   return ret;
467 }
468
469 static void vl_api_snat_interface_details_t_handler
470   (vl_api_snat_interface_details_t *mp)
471 {
472   snat_test_main_t * sm = &snat_test_main;
473   vat_main_t *vam = sm->vat_main;
474
475   fformat (vam->ofp, "sw_if_index %d %s\n", ntohl (mp->sw_if_index),
476            mp->is_inside ? "in" : "out");
477 }
478
479 static int api_snat_interface_dump(vat_main_t * vam)
480 {
481   vl_api_snat_interface_dump_t * mp;
482   vl_api_snat_control_ping_t *mp_ping;
483   int ret;
484
485   if (vam->json_output)
486     {
487       clib_warning ("JSON output not supported for snat_address_dump");
488       return -99;
489     }
490
491   M(SNAT_INTERFACE_DUMP, mp);
492   S(mp);
493
494   /* Use a control ping for synchronization */
495   M(SNAT_CONTROL_PING, mp_ping);
496   S(mp_ping);
497
498   W (ret);
499   return ret;
500 }
501
502 static int api_snat_set_workers (vat_main_t * vam)
503 {
504   unformat_input_t * i = vam->input;
505   vl_api_snat_set_workers_t * mp;
506   uword *bitmap;
507   int ret;
508
509   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
510     {
511       if (unformat (i, "%U", unformat_bitmap_list, &bitmap))
512         ;
513       else
514         {
515           clib_warning("unknown input '%U'", format_unformat_error, i);
516           return -99;
517         }
518     }
519
520   M(SNAT_SET_WORKERS, mp);
521   mp->worker_mask = clib_host_to_net_u64 (bitmap[0]);
522
523   S(mp);
524   W (ret);
525   return ret;
526 }
527
528 static void vl_api_snat_worker_details_t_handler
529   (vl_api_snat_worker_details_t *mp)
530 {
531   snat_test_main_t * sm = &snat_test_main;
532   vat_main_t *vam = sm->vat_main;
533
534   fformat (vam->ofp, "worker_index %d (%s at lcore %u)\n",
535            ntohl (mp->worker_index), mp->name, ntohl (mp->lcore_id));
536 }
537
538 static int api_snat_worker_dump(vat_main_t * vam)
539 {
540   vl_api_snat_worker_dump_t * mp;
541   vl_api_snat_control_ping_t *mp_ping;
542   int ret;
543
544   if (vam->json_output)
545     {
546       clib_warning ("JSON output not supported for snat_address_dump");
547       return -99;
548     }
549
550   M(SNAT_WORKER_DUMP, mp);
551   S(mp);
552
553   /* Use a control ping for synchronization */
554   M(SNAT_CONTROL_PING, mp_ping);
555   S(mp_ping);
556
557   W (ret);
558   return ret;
559 }
560
561 static int api_snat_add_del_interface_addr (vat_main_t * vam)
562 {
563   unformat_input_t * i = vam->input;
564   vl_api_snat_add_del_interface_addr_t * mp;
565   u32 sw_if_index;
566   u8 sw_if_index_set = 0;
567   u8 is_add = 1;
568   int ret;
569
570   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
571     {
572       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
573         sw_if_index_set = 1;
574       else if (unformat (i, "sw_if_index %d", &sw_if_index))
575         sw_if_index_set = 1;
576       else if (unformat (i, "del"))
577         is_add = 0;
578       else
579         {
580           clib_warning("unknown input '%U'", format_unformat_error, i);
581           return -99;
582         }
583     }
584
585   if (sw_if_index_set == 0)
586     {
587       errmsg ("interface / sw_if_index required\n");
588       return -99;
589     }
590
591   M(SNAT_ADD_DEL_INTERFACE_ADDR, mp);
592   mp->sw_if_index = ntohl(sw_if_index);
593   mp->is_add = is_add;
594   
595   S(mp);
596   W (ret);
597   return ret;
598 }
599
600 static void vl_api_snat_interface_addr_details_t_handler
601   (vl_api_snat_interface_addr_details_t *mp)
602 {
603   snat_test_main_t * sm = &snat_test_main;
604   vat_main_t *vam = sm->vat_main;
605
606   fformat (vam->ofp, "sw_if_index %d\n", ntohl (mp->sw_if_index));
607 }
608
609 static int api_snat_interface_addr_dump(vat_main_t * vam)
610 {
611   vl_api_snat_interface_addr_dump_t * mp;
612   vl_api_snat_control_ping_t *mp_ping;
613   int ret;
614
615   if (vam->json_output)
616     {
617       clib_warning ("JSON output not supported for snat_address_dump");
618       return -99;
619     }
620
621   M(SNAT_INTERFACE_ADDR_DUMP, mp);
622   S(mp);
623
624   /* Use a control ping for synchronization */
625   M(SNAT_CONTROL_PING, mp_ping);
626   S(mp_ping);
627
628   W (ret);
629   return ret;
630 }
631
632 static int api_snat_ipfix_enable_disable (vat_main_t * vam)
633 {
634   unformat_input_t * i = vam->input;
635   vl_api_snat_ipfix_enable_disable_t * mp;
636   u32 domain_id = 0;
637   u32 src_port = 0;
638   u8 enable = 1;
639   int ret;
640
641   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
642     {
643       if (unformat (i, "domain %d", &domain_id))
644         ;
645       else if (unformat (i, "src_port %d", &src_port))
646         ;
647       else if (unformat (i, "disable"))
648         enable = 0;
649       else
650         {
651           clib_warning("unknown input '%U'", format_unformat_error, i);
652           return -99;
653         }
654     }
655
656   M(SNAT_IPFIX_ENABLE_DISABLE, mp);
657   mp->domain_id = htonl(domain_id);
658   mp->src_port = htons((u16) src_port);
659   mp->enable = enable;
660
661   S(mp);
662   W (ret);
663   return ret;
664 }
665
666 static void vl_api_snat_user_session_details_t_handler
667   (vl_api_snat_user_session_details_t *mp)
668 {
669   snat_test_main_t * sm = &snat_test_main;
670   vat_main_t *vam = sm->vat_main;
671
672   fformat(vam->ofp, "%s session %U:%d to %U:%d protocol id %d "
673                     "total packets %d total bytes %d\n",
674           mp->is_static ? "static" : "dynamic",
675           format_ip4_address, mp->inside_ip_address, ntohl(mp->inside_port),
676           format_ip4_address, mp->outside_ip_address, ntohl(mp->outside_port),
677           ntohl(mp->protocol), ntohl(mp->total_pkts), ntohl(mp->total_bytes));
678 }
679
680 static int api_snat_user_session_dump(vat_main_t * vam)
681 {
682   unformat_input_t* i = vam->input;
683   vl_api_snat_user_session_dump_t * mp;
684   vl_api_snat_control_ping_t *mp_ping;
685   ip4_address_t addr;
686   u32 vrf_id = ~0;
687   int ret;
688
689   if (vam->json_output)
690     {
691       clib_warning ("JSON output not supported for snat_address_dump");
692       return -99;
693     }
694
695   if (unformat (i, "ip_address %U vrf_id %d",
696                 unformat_ip4_address, &addr, &vrf_id))
697     ;
698   else
699     {
700       clib_warning("unknown input '%U'", format_unformat_error, i);
701       return -99;
702     }
703
704   M(SNAT_USER_SESSION_DUMP, mp);
705   S(mp);
706
707   /* Use a control ping for synchronization */
708   M(SNAT_CONTROL_PING, mp_ping);
709   memset(mp->ip_address, 0, 16);
710   clib_memcpy(mp->ip_address, &addr, 4);
711   mp->vrf_id = htonl(vrf_id);
712   mp->is_ip4 = 1;
713   S(mp_ping);
714
715   W (ret);
716   return ret;
717 }
718
719 static void vl_api_snat_user_details_t_handler
720   (vl_api_snat_user_details_t *mp)
721 {
722   snat_test_main_t * sm = &snat_test_main;
723   vat_main_t *vam = sm->vat_main;
724
725   fformat(vam->ofp, "user with ip %U with vrf_id %d "
726                     "with %d sessions and %d static sessions\n",
727           format_ip4_address, mp->ip_address, ntohl(mp->vrf_id),
728           ntohl(mp->nsessions), ntohl(mp->nstaticsessions));
729 }
730
731 static int api_snat_user_dump(vat_main_t * vam)
732 {
733   vl_api_snat_user_dump_t * mp;
734   vl_api_snat_control_ping_t *mp_ping;
735   int ret;
736
737   if (vam->json_output)
738     {
739       clib_warning ("JSON output not supported for snat_address_dump");
740       return -99;
741     }
742
743   M(SNAT_USER_DUMP, mp);
744   S(mp);
745
746   /* Use a control ping for synchronization */
747   M(SNAT_CONTROL_PING, mp_ping);
748   S(mp_ping);
749
750   W (ret);
751   return ret;
752 }
753
754 static int api_snat_add_det_map (vat_main_t * vam)
755 {
756   unformat_input_t * i = vam->input;
757   vl_api_snat_add_det_map_t * mp;
758   ip4_address_t in_addr, out_addr;
759   u32 in_plen, out_plen;
760   u8 is_add = 1;
761   int ret;
762
763   if (unformat (i, "in %U/%d out %U/%d",
764                 unformat_ip4_address, &in_addr, &in_plen,
765                 unformat_ip4_address, &out_addr, &out_plen))
766     ;
767   else if (unformat (i, "del"))
768     is_add = 0;
769   else
770     {
771       clib_warning("unknown input '%U'", format_unformat_error, i);
772       return -99;
773     }
774
775   M(SNAT_ADD_DET_MAP, mp);
776   clib_memcpy(mp->in_addr, &in_addr, 4);
777   mp->in_plen = in_plen;
778   clib_memcpy(mp->out_addr, &out_addr, 4);
779   mp->out_plen = out_plen;
780   mp->is_add = is_add;
781
782   S(mp);
783   W (ret);
784   return ret;
785 }
786
787 static void vl_api_snat_det_forward_reply_t_handler
788   (vl_api_snat_det_forward_reply_t *mp)
789 {
790   snat_test_main_t * sm = &snat_test_main;
791   vat_main_t *vam = sm->vat_main;
792   i32 retval = ntohl(mp->retval);
793
794   if (retval >= 0)
795   {
796     fformat (vam->ofp, "outside address %U", format_ip4_address, &mp->out_addr);
797     fformat (vam->ofp, " outside port range start %d", ntohs(mp->out_port_lo));
798     fformat (vam->ofp, " outside port range end %d\n", ntohs(mp->out_port_hi));
799   }
800
801   vam->retval = retval;
802   vam->result_ready = 1;
803 }
804
805 static int api_snat_det_forward (vat_main_t * vam)
806 {
807   unformat_input_t * i = vam->input;
808   vl_api_snat_det_forward_t * mp;
809   ip4_address_t in_addr;
810   int ret;
811
812   if (unformat (i, "%U", unformat_ip4_address, &in_addr))
813     ;
814   else
815     {
816       clib_warning("unknown input '%U'", format_unformat_error, i);
817       return -99;
818     }
819
820   M(SNAT_DET_FORWARD, mp);
821   clib_memcpy(mp->in_addr, &in_addr, 4);
822
823   S(mp);
824   W(ret);
825   return ret;
826 }
827
828 static void vl_api_snat_det_reverse_reply_t_handler
829   (vl_api_snat_det_reverse_reply_t *mp)
830 {
831   snat_test_main_t * sm = &snat_test_main;
832   vat_main_t *vam = sm->vat_main;
833   i32 retval = ntohl(mp->retval);
834
835   if (retval >= 0)
836   {
837     fformat (vam->ofp, "inside address %U\n", format_ip4_address, &mp->in_addr);
838   }
839
840   vam->retval = retval;
841   vam->result_ready = 1;
842 }
843
844 static int api_snat_det_reverse (vat_main_t * vam)
845 {
846   unformat_input_t * i = vam->input;
847   vl_api_snat_det_reverse_t * mp;
848   ip4_address_t out_addr;
849   u32 out_port;
850   int ret;
851
852   if (unformat (i, "%U %d", unformat_ip4_address, &out_addr, &out_port))
853     ;
854   else
855     {
856       clib_warning("unknown input '%U'", format_unformat_error, i);
857       return -99;
858     }
859
860   M(SNAT_DET_REVERSE, mp);
861   clib_memcpy(mp->out_addr, &out_addr, 4);
862   mp->out_port = htons((u16)out_port);
863
864   S(mp);
865   W(ret);
866   return ret;
867 }
868
869 static void vl_api_snat_det_map_details_t_handler
870   (vl_api_snat_det_map_details_t *mp)
871 {
872   snat_test_main_t * sm = &snat_test_main;
873   vat_main_t *vam = sm->vat_main;
874
875   fformat (vam->ofp, "Deterministic S-NAT mapping in %U/%d out %U/%d "
876                      "ports per host %d sharing ratio %d "
877                      "number of sessions %d",
878            format_ip4_address, mp->in_addr, mp->in_plen,
879            format_ip4_address, mp->out_addr, mp->out_plen,
880            ntohs(mp->ports_per_host), ntohl(mp->sharing_ratio),
881            ntohl(mp->ses_num));
882 }
883
884 static int api_snat_det_map_dump(vat_main_t * vam)
885 {
886   vl_api_snat_det_map_dump_t * mp;
887   vl_api_snat_control_ping_t *mp_ping;
888   int ret;
889
890   if (vam->json_output)
891     {
892       clib_warning ("JSON output not supported for snat_det_map_dump");
893       return -99;
894     }
895
896   M(SNAT_DET_MAP_DUMP, mp);
897   S(mp);
898
899   /* Use a control ping for synchronization */
900   M(SNAT_CONTROL_PING, mp_ping);
901   S(mp_ping);
902
903   W (ret);
904   return ret;
905 }
906
907 static int api_snat_det_set_timeouts (vat_main_t * vam)
908 {
909   unformat_input_t * i = vam->input;
910   vl_api_snat_det_set_timeouts_t * mp;
911   u32 udp = SNAT_UDP_TIMEOUT;
912   u32 tcp_established = SNAT_TCP_ESTABLISHED_TIMEOUT;
913   u32 tcp_transitory = SNAT_TCP_TRANSITORY_TIMEOUT;
914   u32 icmp = SNAT_ICMP_TIMEOUT;
915   int ret;
916
917   if (unformat (i, "udp %d", &udp))
918     ;
919   else if (unformat (i, "tcp_established %d", &tcp_established))
920     ;
921   else if (unformat (i, "tcp_transitory %d", &tcp_transitory))
922     ;
923   else if (unformat (i, "icmp %d", &icmp))
924     ;
925   else
926     {
927       clib_warning("unknown input '%U'", format_unformat_error, i);
928       return -99;
929     }
930
931   M(SNAT_DET_SET_TIMEOUTS, mp);
932   mp->udp = htonl(udp);
933   mp->tcp_established = htonl(tcp_established);
934   mp->tcp_transitory = htonl(tcp_transitory);
935   mp->icmp = htonl(icmp);
936
937   S(mp);
938   W (ret);
939   return ret;
940 }
941
942 static void vl_api_snat_det_get_timeouts_reply_t_handler
943   (vl_api_snat_det_get_timeouts_reply_t *mp)
944 {
945   snat_test_main_t * sm = &snat_test_main;
946   vat_main_t *vam = sm->vat_main;
947   i32 retval = ntohl (mp->retval);
948
949   if (retval >= 0)
950     {
951       fformat (vam->ofp, "udp timeout: %dsec\n", ntohl (mp->udp));
952       fformat (vam->ofp, "tcp-established timeout: %dsec",
953                ntohl (mp->tcp_established));
954       fformat (vam->ofp, "tcp-transitory timeout: %dsec",
955                ntohl (mp->tcp_transitory));
956       fformat (vam->ofp, "icmp timeout: %dsec", ntohl (mp->icmp));
957     }
958   vam->retval = retval;
959   vam->result_ready = 1;
960 }
961
962 static int api_snat_det_get_timeouts(vat_main_t * vam)
963 {
964   vl_api_snat_det_get_timeouts_t * mp;
965   int ret;
966
967   if (vam->json_output)
968     {
969       clib_warning ("JSON output not supported for snat_show_config");
970       return -99;
971     }
972
973   M(SNAT_DET_GET_TIMEOUTS, mp);
974   S(mp);
975   W (ret);
976   return ret;
977 }
978
979 static int api_snat_det_close_session_out (vat_main_t * vam)
980 {
981   unformat_input_t * i = vam->input;
982   vl_api_snat_det_close_session_out_t * mp;
983   ip4_address_t out_addr, ext_addr;
984   u32 out_port, ext_port;
985   int ret;
986
987   if (unformat (i, "%U:%d %U:%d",
988                 unformat_ip4_address, &out_addr, &out_port,
989                 unformat_ip4_address, &ext_addr, &ext_port))
990     ;
991   else
992     {
993       clib_warning("unknown input '%U'", format_unformat_error, i);
994       return -99;
995     }
996
997   M(SNAT_DET_CLOSE_SESSION_OUT, mp);
998   clib_memcpy(mp->out_addr, &out_addr, 4);
999   mp->out_port = ntohs((u16)out_port);
1000   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1001   mp->ext_port = ntohs((u16)ext_port);
1002
1003   S(mp);
1004   W (ret);
1005   return ret;
1006 }
1007
1008 static int api_snat_det_close_session_in (vat_main_t * vam)
1009 {
1010   unformat_input_t * i = vam->input;
1011   vl_api_snat_det_close_session_in_t * mp;
1012   ip4_address_t in_addr, ext_addr;
1013   u32 in_port, ext_port;
1014   int ret;
1015
1016   if (unformat (i, "%U:%d %U:%d",
1017                 unformat_ip4_address, &in_addr, &in_port,
1018                 unformat_ip4_address, &ext_addr, &ext_port))
1019     ;
1020   else
1021     {
1022       clib_warning("unknown input '%U'", format_unformat_error, i);
1023       return -99;
1024     }
1025
1026   M(SNAT_DET_CLOSE_SESSION_IN, mp);
1027   clib_memcpy(mp->in_addr, &in_addr, 4);
1028   mp->in_port = ntohs((u16)in_port);
1029   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1030   mp->ext_port = ntohs((u16)ext_port);
1031
1032   S(mp);
1033   W (ret);
1034   return ret;
1035 }
1036
1037 static void vl_api_snat_det_session_details_t_handler
1038   (vl_api_snat_det_session_details_t *mp)
1039 {
1040   snat_test_main_t * sm = &snat_test_main;
1041   vat_main_t *vam = sm->vat_main;
1042
1043   fformat(vam->ofp, "deterministic session, external host address %U, "
1044                     "external host port %d, outer port %d, inside port %d",
1045           format_ip4_address, mp->ext_addr, mp->ext_port,
1046           mp->out_port, mp->in_port);
1047 }
1048
1049 static int api_snat_det_session_dump(vat_main_t * vam)
1050 {
1051   unformat_input_t* i = vam->input;
1052   vl_api_snat_det_session_dump_t * mp;
1053   vl_api_snat_control_ping_t *mp_ping;
1054   ip4_address_t user_addr;
1055   int ret;
1056
1057   if (vam->json_output)
1058     {
1059       clib_warning ("JSON output not supported for snat_det_session_dump");
1060       return -99;
1061     }
1062
1063   if (unformat (i, "user_addr %U", unformat_ip4_address, &user_addr))
1064     ;
1065   else
1066     {
1067       clib_warning ("unknown input '%U'", format_unformat_error, i);
1068       return -99;
1069     }
1070
1071   M(SNAT_DET_SESSION_DUMP, mp);
1072   clib_memcpy (&mp->user_addr, &user_addr, 4);
1073   S(mp);
1074
1075   /* Use a control ping for synchronization */
1076   M(SNAT_CONTROL_PING, mp_ping);
1077   S(mp_ping);
1078
1079   W (ret);
1080   return ret;
1081 }
1082
1083 /* 
1084  * List of messages that the api test plugin sends,
1085  * and that the data plane plugin processes
1086  */
1087 #define foreach_vpe_api_msg                                      \
1088 _(snat_add_address_range, "<start-addr> [- <end-addr] [del]")    \
1089 _(snat_interface_add_del_feature,                                \
1090   "<intfc> | sw_if_index <id> [in] [out] [del]")                 \
1091 _(snat_add_static_mapping, "local_addr <ip> (external_addr <ip>" \
1092   " | external_if <intfc> | external_sw_if_ndex <id>) "          \
1093   "[local_port <n>] [external_port <n>] [vrf <table-id>] [del] " \
1094   "protocol <n>")                                                \
1095 _(snat_set_workers, "<wokrers_bitmap>")                          \
1096 _(snat_static_mapping_dump, "")                                  \
1097 _(snat_show_config, "")                                          \
1098 _(snat_address_dump, "")                                         \
1099 _(snat_interface_dump, "")                                       \
1100 _(snat_worker_dump, "")                                          \
1101 _(snat_add_del_interface_addr,                                   \
1102   "<intfc> | sw_if_index <id> [del]")                            \
1103 _(snat_interface_addr_dump, "")                                  \
1104 _(snat_ipfix_enable_disable, "[domain <id>] [src_port <n>] "     \
1105   "[disable]")                                                   \
1106 _(snat_user_dump, "")                                            \
1107 _(snat_user_session_dump, "ip_address <ip> vrf_id <table-id>")   \
1108 _(snat_add_det_map, "in <in_addr>/<in_plen> out "                \
1109   "<out_addr>/<out_plen> [del]")                                 \
1110 _(snat_det_forward, "<in_addr>")                                 \
1111 _(snat_det_reverse, "<out_addr> <out_port>")                     \
1112 _(snat_det_map_dump, "")                                         \
1113 _(snat_det_set_timeouts, "[udp <sec> | tcp_established <sec> | " \
1114   "tcp_transitory <sec> | icmp <sec>]")                          \
1115 _(snat_det_get_timeouts, "")                                     \
1116 _(snat_det_close_session_out, "<out_addr>:<out_port> "           \
1117   "<ext_addr>:<ext_port>")                                       \
1118 _(snat_det_close_session_in, "<in_addr>:<in_port> "              \
1119   "<out_addr>:<out_port>")                                       \
1120 _(snat_det_session_dump, "ip_address <user_addr>")
1121
1122 static void 
1123 snat_vat_api_hookup (vat_main_t *vam)
1124 {
1125   snat_test_main_t * sm __attribute__((unused)) = &snat_test_main;
1126   /* Hook up handlers for replies from the data plane plug-in */
1127 #define _(N,n)                                                  \
1128   vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),       \
1129                           #n,                                   \
1130                           vl_api_##n##_t_handler,               \
1131                           vl_noop_handler,                      \
1132                           vl_api_##n##_t_endian,                \
1133                           vl_api_##n##_t_print,                 \
1134                           sizeof(vl_api_##n##_t), 1); 
1135   foreach_vpe_api_reply_msg;
1136 #undef _
1137
1138   /* API messages we can send */
1139 #define _(n,h)                                          \
1140   hash_set_mem (vam->function_by_name, #n, api_##n);
1141   foreach_vpe_api_msg;
1142 #undef _    
1143     
1144   /* Help strings */
1145 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
1146   foreach_vpe_api_msg;
1147 #undef _
1148 }
1149
1150 clib_error_t * vat_plugin_register (vat_main_t *vam)
1151 {
1152   snat_test_main_t * sm = &snat_test_main;
1153   u8 * name;
1154
1155   sm->vat_main = vam;
1156
1157   /* Ask the vpp engine for the first assigned message-id */
1158   name = format (0, "snat_%08x%c", api_version, 0);
1159   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
1160
1161   if (sm->msg_id_base != (u16) ~0)
1162     snat_vat_api_hookup (vam);
1163   
1164   vec_free(name);
1165   
1166   return 0;
1167 }