Proxy ND (RFC4389 - or a sub-set thereof). This allows the 'emulation' of bridging...
[vpp.git] / src / plugins / snat / snat_test.c
1
2 /*
3  * snat.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
25 #define __plugin_msg_base snat_test_main.msg_id_base
26 #include <vlibapi/vat_helper_macros.h>
27
28 uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
29
30 /* Declare message IDs */
31 #include <snat/snat_msg_enum.h>
32
33 /* define message structures */
34 #define vl_typedefs
35 #include <snat/snat_all_api_h.h> 
36 #undef vl_typedefs
37
38 /* declare message handlers for each api */
39
40 #define vl_endianfun             /* define message structures */
41 #include <snat/snat_all_api_h.h> 
42 #undef vl_endianfun
43
44 /* instantiate all the print functions we know about */
45 #define vl_print(handle, ...)
46 #define vl_printfun
47 #include <snat/snat_all_api_h.h> 
48 #undef vl_printfun
49
50 /* Get the API version number. */
51 #define vl_api_version(n,v) static u32 api_version=(v);
52 #include <snat/snat_all_api_h.h>
53 #undef vl_api_version
54
55 typedef struct {
56     /* API message ID base */
57     u16 msg_id_base;
58     vat_main_t *vat_main;
59 } snat_test_main_t;
60
61 snat_test_main_t snat_test_main;
62
63 #define foreach_standard_reply_retval_handler   \
64 _(snat_add_address_range_reply)                 \
65 _(snat_interface_add_del_feature_reply)         \
66 _(snat_add_static_mapping_reply)                \
67 _(snat_set_workers_reply)                       \
68 _(snat_add_del_interface_addr_reply)            \
69 _(snat_ipfix_enable_disable_reply)              \
70 _(snat_add_det_map_reply)
71
72 #define _(n)                                            \
73     static void vl_api_##n##_t_handler                  \
74     (vl_api_##n##_t * mp)                               \
75     {                                                   \
76         vat_main_t * vam = snat_test_main.vat_main;   \
77         i32 retval = ntohl(mp->retval);                 \
78         if (vam->async_mode) {                          \
79             vam->async_errors += (retval < 0);          \
80         } else {                                        \
81             vam->retval = retval;                       \
82             vam->result_ready = 1;                      \
83         }                                               \
84     }
85 foreach_standard_reply_retval_handler;
86 #undef _
87
88 /* 
89  * Table of message reply handlers, must include boilerplate handlers
90  * we just generated
91  */
92 #define foreach_vpe_api_reply_msg                               \
93 _(SNAT_ADD_ADDRESS_RANGE_REPLY, snat_add_address_range_reply)   \
94 _(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY,                         \
95   snat_interface_add_del_feature_reply)                         \
96 _(SNAT_ADD_STATIC_MAPPING_REPLY, snat_add_static_mapping_reply) \
97 _(SNAT_CONTROL_PING_REPLY, snat_control_ping_reply)             \
98 _(SNAT_STATIC_MAPPING_DETAILS, snat_static_mapping_details)     \
99 _(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply)               \
100 _(SNAT_ADDRESS_DETAILS, snat_address_details)                   \
101 _(SNAT_INTERFACE_DETAILS, snat_interface_details)               \
102 _(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply)               \
103 _(SNAT_WORKER_DETAILS, snat_worker_details)                     \
104 _(SNAT_ADD_DEL_INTERFACE_ADDR_REPLY,                            \
105   snat_add_del_interface_addr_reply)                            \
106 _(SNAT_INTERFACE_ADDR_DETAILS, snat_interface_addr_details)     \
107 _(SNAT_IPFIX_ENABLE_DISABLE_REPLY,                              \
108   snat_ipfix_enable_disable_reply)                              \
109 _(SNAT_USER_DETAILS, snat_user_details)                         \
110 _(SNAT_USER_SESSION_DETAILS, snat_user_session_details)         \
111 _(SNAT_ADD_DET_MAP_REPLY, snat_add_det_map_reply)               \
112 _(SNAT_DET_FORWARD_REPLY, snat_det_forward_reply)               \
113 _(SNAT_DET_REVERSE_REPLY, snat_det_reverse_reply)
114
115 static int api_snat_add_address_range (vat_main_t * vam)
116 {
117   unformat_input_t * i = vam->input;
118   ip4_address_t start_addr, end_addr;
119   u32 start_host_order, end_host_order;
120   vl_api_snat_add_address_range_t * mp;
121   u8 is_add = 1;
122   int count;
123   int ret;
124
125   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
126     {
127       if (unformat (i, "%U - %U",
128                     unformat_ip4_address, &start_addr,
129                     unformat_ip4_address, &end_addr))
130         ;
131       else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
132         end_addr = start_addr;
133       else if (unformat (i, "del"))
134         is_add = 0;
135       else
136         {
137           clib_warning("unknown input '%U'", format_unformat_error, i);
138           return -99;
139         }
140     }
141
142   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
143   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
144   
145   if (end_host_order < start_host_order)
146     {
147       errmsg ("end address less than start address\n");
148       return -99;
149     }
150
151   count = (end_host_order - start_host_order) + 1;
152
153   if (count > 1024)
154     {
155     errmsg ("%U - %U, %d addresses...\n",
156            format_ip4_address, &start_addr,
157            format_ip4_address, &end_addr,
158            count);
159     }
160   
161   M(SNAT_ADD_ADDRESS_RANGE, mp);
162
163   memcpy (mp->first_ip_address, &start_addr, 4);
164   memcpy (mp->last_ip_address, &end_addr, 4);
165   mp->is_ip4 = 1;
166   mp->is_add = is_add;
167
168   S(mp);
169   W (ret);
170   return ret;
171 }
172
173 static int api_snat_interface_add_del_feature (vat_main_t * vam)
174 {
175   unformat_input_t * i = vam->input;
176   vl_api_snat_interface_add_del_feature_t * mp;
177   u32 sw_if_index;
178   u8 sw_if_index_set = 0;
179   u8 is_inside = 1; 
180   u8 is_add = 1;
181   int ret;
182
183   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
184     {
185       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
186         sw_if_index_set = 1;
187       else if (unformat (i, "sw_if_index %d", &sw_if_index))
188         sw_if_index_set = 1;
189       else if (unformat (i, "out"))
190         is_inside = 0;
191       else if (unformat (i, "in"))
192         is_inside = 1;
193       else if (unformat (i, "del"))
194         is_add = 0;
195       else
196         {
197           clib_warning("unknown input '%U'", format_unformat_error, i);
198           return -99;
199         }
200     }
201
202   if (sw_if_index_set == 0)
203     {
204       errmsg ("interface / sw_if_index required\n");
205       return -99;
206     }
207
208   M(SNAT_INTERFACE_ADD_DEL_FEATURE, mp);
209   mp->sw_if_index = ntohl(sw_if_index);
210   mp->is_add = is_add;
211   mp->is_inside = is_inside;
212   
213   S(mp);
214   W (ret);
215   return ret;
216 }
217
218 static int api_snat_add_static_mapping(vat_main_t * vam)
219 {
220   unformat_input_t * i = vam->input;
221   vl_api_snat_add_static_mapping_t * mp;
222   u8 external_addr_set = 0;
223   u8 local_addr_set = 0;
224   u8 is_add = 1;
225   u8 addr_only = 1;
226   ip4_address_t local_addr, external_addr;
227   u32 local_port = 0, external_port = 0, vrf_id = ~0;
228   u32 sw_if_index = ~0;
229   u8 sw_if_index_set = 0;
230   u32 proto = ~0;
231   u8 proto_set = 0;
232   int ret;
233
234   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
235     {
236       if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr))
237         local_addr_set = 1;
238       else if (unformat (i, "external_addr %U", unformat_ip4_address,
239                          &external_addr))
240         external_addr_set = 1;
241       else if (unformat (i, "local_port %u", &local_port))
242         addr_only = 0;
243       else if (unformat (i, "external_port %u", &external_port))
244         addr_only = 0;
245       else if (unformat (i, "external_if %U", unformat_sw_if_index, vam,
246                          &sw_if_index))
247         sw_if_index_set = 1;
248       else if (unformat (i, "external_sw_if_index %d", &sw_if_index))
249         sw_if_index_set = 1;
250       else if (unformat (i, "vrf %u", &vrf_id))
251         ;
252       else if (unformat (i, "protocol %u", &proto))
253         proto_set = 1;
254       else if (unformat (i, "del"))
255         is_add = 0;
256       else
257         {
258           clib_warning("unknown input '%U'", format_unformat_error, i);
259           return -99;
260         }
261     }
262
263   if (!addr_only && !proto_set)
264     {
265       errmsg ("protocol required\n");
266       return -99;
267     }
268
269   if (!local_addr_set)
270     {
271       errmsg ("local addr required\n");
272       return -99;
273     }
274   if (!external_addr_set && !sw_if_index_set)
275     {
276       errmsg ("external addr or interface required\n");
277       return -99;
278     }
279
280   M(SNAT_ADD_STATIC_MAPPING, mp);
281   mp->is_add = is_add;
282   mp->is_ip4 = 1;
283   mp->addr_only = addr_only;
284   mp->local_port = ntohs ((u16) local_port);
285   mp->external_port = ntohs ((u16) external_port);
286   mp->external_sw_if_index = ntohl (sw_if_index);
287   mp->vrf_id = ntohl (vrf_id);
288   mp->protocol = (u8) proto;
289   memcpy (mp->local_ip_address, &local_addr, 4);
290   memcpy (mp->external_ip_address, &external_addr, 4);
291
292   S(mp);
293   W (ret);
294   return ret;
295 }
296
297 static void vl_api_snat_control_ping_reply_t_handler
298   (vl_api_snat_control_ping_reply_t * mp)
299 {
300   vat_main_t *vam = &vat_main;
301   i32 retval = ntohl (mp->retval);
302   if (vam->async_mode)
303     {
304       vam->async_errors += (retval < 0);
305     }
306   else
307     {
308       vam->retval = retval;
309       vam->result_ready = 1;
310     }
311 }
312
313 static void vl_api_snat_static_mapping_details_t_handler
314   (vl_api_snat_static_mapping_details_t *mp)
315 {
316   snat_test_main_t * sm = &snat_test_main;
317   vat_main_t *vam = sm->vat_main;
318
319   if (mp->addr_only && mp->external_sw_if_index != ~0)
320       fformat (vam->ofp, "%15U%6s%15d%6s%11d%6d\n",
321                format_ip4_address, &mp->local_ip_address, "",
322                ntohl (mp->external_sw_if_index), "",
323                ntohl (mp->vrf_id),
324                mp->protocol);
325   else if (mp->addr_only && mp->external_sw_if_index == ~0)
326       fformat (vam->ofp, "%15U%6s%15U%6s%11d%6d\n",
327                format_ip4_address, &mp->local_ip_address, "",
328                format_ip4_address, &mp->external_ip_address, "",
329                ntohl (mp->vrf_id),
330                mp->protocol);
331   else if (!mp->addr_only && mp->external_sw_if_index != ~0)
332       fformat (vam->ofp, "%15U%6d%15d%6d%11d%6d\n",
333                format_ip4_address, &mp->local_ip_address,
334                ntohs (mp->local_port),
335                ntohl (mp->external_sw_if_index),
336                ntohs (mp->external_port),
337                ntohl (mp->vrf_id),
338                mp->protocol);
339   else
340       fformat (vam->ofp, "%15U%6d%15U%6d%11d%6d\n",
341                format_ip4_address, &mp->local_ip_address,
342                ntohs (mp->local_port),
343                format_ip4_address, &mp->external_ip_address,
344                ntohs (mp->external_port),
345                ntohl (mp->vrf_id),
346                mp->protocol);
347
348 }
349
350 static int api_snat_static_mapping_dump(vat_main_t * vam)
351 {
352   vl_api_snat_static_mapping_dump_t * mp;
353   vl_api_snat_control_ping_t *mp_ping;
354   int ret;
355
356   if (vam->json_output)
357     {
358       clib_warning ("JSON output not supported for snat_static_mapping_dump");
359       return -99;
360     }
361
362   fformat (vam->ofp, "%21s%21s\n", "local", "external");
363   fformat (vam->ofp, "%15s%6s%15s%6s%11s%6s\n", "address", "port",
364            "address/if_idx", "port", "vrf", "proto");
365
366   M(SNAT_STATIC_MAPPING_DUMP, mp);
367   S(mp);
368
369   /* Use a control ping for synchronization */
370   M(SNAT_CONTROL_PING, mp_ping);
371   S(mp_ping);
372
373   W (ret);
374   return ret;
375 }
376
377 static void vl_api_snat_show_config_reply_t_handler
378   (vl_api_snat_show_config_reply_t *mp)
379 {
380   snat_test_main_t * sm = &snat_test_main;
381   vat_main_t *vam = sm->vat_main;
382   i32 retval = ntohl (mp->retval);
383
384   if (retval >= 0)
385     {
386       fformat (vam->ofp, "translation hash buckets %d\n",
387                ntohl (mp->translation_buckets));
388       fformat (vam->ofp, "translation hash memory %d\n",
389                ntohl (mp->translation_memory_size));
390       fformat (vam->ofp, "user hash buckets %d\n", ntohl (mp->user_buckets));
391       fformat (vam->ofp, "user hash memory %d\n", ntohl (mp->user_memory_size));
392       fformat (vam->ofp, "max translations per user %d\n",
393                ntohl (mp->max_translations_per_user));
394       fformat (vam->ofp, "outside VRF id %d\n", ntohl (mp->outside_vrf_id));
395       fformat (vam->ofp, "inside VRF id %d\n", ntohl (mp->inside_vrf_id));
396       if (mp->static_mapping_only)
397         {
398           fformat (vam->ofp, "static mapping only");
399           if (mp->static_mapping_connection_tracking)
400             fformat (vam->ofp, " connection tracking");
401           fformat (vam->ofp, "\n");
402         }
403     }
404   vam->retval = retval;
405   vam->result_ready = 1;
406 }
407
408 static int api_snat_show_config(vat_main_t * vam)
409 {
410   vl_api_snat_show_config_t * mp;
411   int ret;
412
413   if (vam->json_output)
414     {
415       clib_warning ("JSON output not supported for snat_show_config");
416       return -99;
417     }
418
419   M(SNAT_SHOW_CONFIG, mp);
420   S(mp);
421   W (ret);
422   return ret;
423 }
424
425 static void vl_api_snat_address_details_t_handler
426   (vl_api_snat_address_details_t *mp)
427 {
428   snat_test_main_t * sm = &snat_test_main;
429   vat_main_t *vam = sm->vat_main;
430
431   fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address);
432 }
433
434 static int api_snat_address_dump(vat_main_t * vam)
435 {
436   vl_api_snat_address_dump_t * mp;
437   vl_api_snat_control_ping_t *mp_ping;
438   int ret;
439
440   if (vam->json_output)
441     {
442       clib_warning ("JSON output not supported for snat_address_dump");
443       return -99;
444     }
445
446   M(SNAT_ADDRESS_DUMP, mp);
447   S(mp);
448
449   /* Use a control ping for synchronization */
450   M(SNAT_CONTROL_PING, mp_ping);
451   S(mp_ping);
452
453   W (ret);
454   return ret;
455 }
456
457 static void vl_api_snat_interface_details_t_handler
458   (vl_api_snat_interface_details_t *mp)
459 {
460   snat_test_main_t * sm = &snat_test_main;
461   vat_main_t *vam = sm->vat_main;
462
463   fformat (vam->ofp, "sw_if_index %d %s\n", ntohl (mp->sw_if_index),
464            mp->is_inside ? "in" : "out");
465 }
466
467 static int api_snat_interface_dump(vat_main_t * vam)
468 {
469   vl_api_snat_interface_dump_t * mp;
470   vl_api_snat_control_ping_t *mp_ping;
471   int ret;
472
473   if (vam->json_output)
474     {
475       clib_warning ("JSON output not supported for snat_address_dump");
476       return -99;
477     }
478
479   M(SNAT_INTERFACE_DUMP, mp);
480   S(mp);
481
482   /* Use a control ping for synchronization */
483   M(SNAT_CONTROL_PING, mp_ping);
484   S(mp_ping);
485
486   W (ret);
487   return ret;
488 }
489
490 static int api_snat_set_workers (vat_main_t * vam)
491 {
492   unformat_input_t * i = vam->input;
493   vl_api_snat_set_workers_t * mp;
494   uword *bitmap;
495   int ret;
496
497   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
498     {
499       if (unformat (i, "%U", unformat_bitmap_list, &bitmap))
500         ;
501       else
502         {
503           clib_warning("unknown input '%U'", format_unformat_error, i);
504           return -99;
505         }
506     }
507
508   M(SNAT_SET_WORKERS, mp);
509   mp->worker_mask = clib_host_to_net_u64 (bitmap[0]);
510
511   S(mp);
512   W (ret);
513   return ret;
514 }
515
516 static void vl_api_snat_worker_details_t_handler
517   (vl_api_snat_worker_details_t *mp)
518 {
519   snat_test_main_t * sm = &snat_test_main;
520   vat_main_t *vam = sm->vat_main;
521
522   fformat (vam->ofp, "worker_index %d (%s at lcore %u)\n",
523            ntohl (mp->worker_index), mp->name, ntohl (mp->lcore_id));
524 }
525
526 static int api_snat_worker_dump(vat_main_t * vam)
527 {
528   vl_api_snat_worker_dump_t * mp;
529   vl_api_snat_control_ping_t *mp_ping;
530   int ret;
531
532   if (vam->json_output)
533     {
534       clib_warning ("JSON output not supported for snat_address_dump");
535       return -99;
536     }
537
538   M(SNAT_WORKER_DUMP, mp);
539   S(mp);
540
541   /* Use a control ping for synchronization */
542   M(SNAT_CONTROL_PING, mp_ping);
543   S(mp_ping);
544
545   W (ret);
546   return ret;
547 }
548
549 static int api_snat_add_del_interface_addr (vat_main_t * vam)
550 {
551   unformat_input_t * i = vam->input;
552   vl_api_snat_add_del_interface_addr_t * mp;
553   u32 sw_if_index;
554   u8 sw_if_index_set = 0;
555   u8 is_add = 1;
556   int ret;
557
558   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
559     {
560       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
561         sw_if_index_set = 1;
562       else if (unformat (i, "sw_if_index %d", &sw_if_index))
563         sw_if_index_set = 1;
564       else if (unformat (i, "del"))
565         is_add = 0;
566       else
567         {
568           clib_warning("unknown input '%U'", format_unformat_error, i);
569           return -99;
570         }
571     }
572
573   if (sw_if_index_set == 0)
574     {
575       errmsg ("interface / sw_if_index required\n");
576       return -99;
577     }
578
579   M(SNAT_ADD_DEL_INTERFACE_ADDR, mp);
580   mp->sw_if_index = ntohl(sw_if_index);
581   mp->is_add = is_add;
582   
583   S(mp);
584   W (ret);
585   return ret;
586 }
587
588 static void vl_api_snat_interface_addr_details_t_handler
589   (vl_api_snat_interface_addr_details_t *mp)
590 {
591   snat_test_main_t * sm = &snat_test_main;
592   vat_main_t *vam = sm->vat_main;
593
594   fformat (vam->ofp, "sw_if_index %d\n", ntohl (mp->sw_if_index));
595 }
596
597 static int api_snat_interface_addr_dump(vat_main_t * vam)
598 {
599   vl_api_snat_interface_addr_dump_t * mp;
600   vl_api_snat_control_ping_t *mp_ping;
601   int ret;
602
603   if (vam->json_output)
604     {
605       clib_warning ("JSON output not supported for snat_address_dump");
606       return -99;
607     }
608
609   M(SNAT_INTERFACE_ADDR_DUMP, mp);
610   S(mp);
611
612   /* Use a control ping for synchronization */
613   M(SNAT_CONTROL_PING, mp_ping);
614   S(mp_ping);
615
616   W (ret);
617   return ret;
618 }
619
620 static int api_snat_ipfix_enable_disable (vat_main_t * vam)
621 {
622   unformat_input_t * i = vam->input;
623   vl_api_snat_ipfix_enable_disable_t * mp;
624   u32 domain_id = 0;
625   u32 src_port = 0;
626   u8 enable = 1;
627   int ret;
628
629   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
630     {
631       if (unformat (i, "domain %d", &domain_id))
632         ;
633       else if (unformat (i, "src_port %d", &src_port))
634         ;
635       else if (unformat (i, "disable"))
636         enable = 0;
637       else
638         {
639           clib_warning("unknown input '%U'", format_unformat_error, i);
640           return -99;
641         }
642     }
643
644   M(SNAT_IPFIX_ENABLE_DISABLE, mp);
645   mp->domain_id = htonl(domain_id);
646   mp->src_port = htons((u16) src_port);
647   mp->enable = enable;
648
649   S(mp);
650   W (ret);
651   return ret;
652 }
653
654 static void vl_api_snat_user_session_details_t_handler
655   (vl_api_snat_user_session_details_t *mp)
656 {
657   snat_test_main_t * sm = &snat_test_main;
658   vat_main_t *vam = sm->vat_main;
659
660   fformat(vam->ofp, "%s session %U:%d to %U:%d protocol id %d "
661                     "total packets %d total bytes %d\n",
662           mp->is_static ? "static" : "dynamic",
663           format_ip4_address, mp->inside_ip_address, ntohl(mp->inside_port),
664           format_ip4_address, mp->outside_ip_address, ntohl(mp->outside_port),
665           ntohl(mp->protocol), ntohl(mp->total_pkts), ntohl(mp->total_bytes));
666 }
667
668 static int api_snat_user_session_dump(vat_main_t * vam)
669 {
670   vl_api_snat_user_session_dump_t * mp;
671   vl_api_snat_control_ping_t *mp_ping;
672   int ret;
673
674   if (vam->json_output)
675     {
676       clib_warning ("JSON output not supported for snat_address_dump");
677       return -99;
678     }
679
680   M(SNAT_USER_SESSION_DUMP, mp);
681   S(mp);
682
683   /* Use a control ping for synchronization */
684   M(SNAT_CONTROL_PING, mp_ping);
685   S(mp_ping);
686
687   W (ret);
688   return ret;
689 }
690
691 static void vl_api_snat_user_details_t_handler
692   (vl_api_snat_user_details_t *mp)
693 {
694   snat_test_main_t * sm = &snat_test_main;
695   vat_main_t *vam = sm->vat_main;
696
697   fformat(vam->ofp, "user with ip %U with vrf_id %d "
698                     "with %d sessions and %d static sessions\n",
699           format_ip4_address, mp->ip_address, ntohl(mp->vrf_id),
700           ntohl(mp->nsessions), ntohl(mp->nstaticsessions));
701 }
702
703 static int api_snat_user_dump(vat_main_t * vam)
704 {
705   vl_api_snat_user_dump_t * mp;
706   vl_api_snat_control_ping_t *mp_ping;
707   int ret;
708
709   if (vam->json_output)
710     {
711       clib_warning ("JSON output not supported for snat_address_dump");
712       return -99;
713     }
714
715   M(SNAT_USER_DUMP, mp);
716   S(mp);
717
718   /* Use a control ping for synchronization */
719   M(SNAT_CONTROL_PING, mp_ping);
720   S(mp_ping);
721
722   W (ret);
723   return ret;
724 }
725
726 static int api_snat_add_det_map (vat_main_t * vam)
727 {
728   unformat_input_t * i = vam->input;
729   vl_api_snat_add_det_map_t * mp;
730   ip4_address_t in_addr, out_addr;
731   u32 in_plen, out_plen;
732   u8 is_add = 1;
733   int ret;
734
735   if (unformat (i, "in %U/%d out %U/%d",
736                 unformat_ip4_address, &in_addr, &in_plen,
737                 unformat_ip4_address, &out_addr, &out_plen))
738     ;
739   else if (unformat (i, "del"))
740     is_add = 0;
741   else
742     {
743       clib_warning("unknown input '%U'", format_unformat_error, i);
744       return -99;
745     }
746
747   M(SNAT_ADD_DET_MAP, mp);
748   clib_memcpy(mp->in_addr, &in_addr, 4);
749   mp->in_plen = in_plen;
750   clib_memcpy(mp->out_addr, &out_addr, 4);
751   mp->out_plen = out_plen;
752   mp->is_add = is_add;
753
754   S(mp);
755   W (ret);
756   return ret;
757 }
758
759 static void vl_api_snat_det_forward_reply_t_handler
760   (vl_api_snat_det_forward_reply_t *mp)
761 {
762   snat_test_main_t * sm = &snat_test_main;
763   vat_main_t *vam = sm->vat_main;
764   i32 retval = ntohl(mp->retval);
765
766   if (retval >= 0)
767   {
768     fformat (vam->ofp, "outside address %U", format_ip4_address, &mp->out_addr);
769     fformat (vam->ofp, " outside port range start %d", ntohs(mp->out_port_lo));
770     fformat (vam->ofp, " outside port range end %d\n", ntohs(mp->out_port_hi));
771   }
772
773   vam->retval = retval;
774   vam->result_ready = 1;
775 }
776
777 static int api_snat_det_forward (vat_main_t * vam)
778 {
779   unformat_input_t * i = vam->input;
780   vl_api_snat_det_forward_t * mp;
781   ip4_address_t in_addr;
782   int ret;
783
784   if (unformat (i, "%U", unformat_ip4_address, &in_addr))
785     ;
786   else
787     {
788       clib_warning("unknown input '%U'", format_unformat_error, i);
789       return -99;
790     }
791
792   M(SNAT_DET_FORWARD, mp);
793   clib_memcpy(mp->in_addr, &in_addr, 4);
794
795   S(mp);
796   W(ret);
797   return ret;
798 }
799
800 static void vl_api_snat_det_reverse_reply_t_handler
801   (vl_api_snat_det_reverse_reply_t *mp)
802 {
803   snat_test_main_t * sm = &snat_test_main;
804   vat_main_t *vam = sm->vat_main;
805   i32 retval = ntohl(mp->retval);
806
807   if (retval >= 0)
808   {
809     fformat (vam->ofp, "inside address %U\n", format_ip4_address, &mp->in_addr);
810   }
811
812   vam->retval = retval;
813   vam->result_ready = 1;
814 }
815
816 static int api_snat_det_reverse (vat_main_t * vam)
817 {
818   unformat_input_t * i = vam->input;
819   vl_api_snat_det_reverse_t * mp;
820   ip4_address_t out_addr;
821   u16 out_port;
822   int ret;
823
824   if (unformat (i, "%U %d", unformat_ip4_address, &out_addr, &out_port))
825     ;
826   else
827     {
828       clib_warning("unknown input '%U'", format_unformat_error, i);
829       return -99;
830     }
831
832   M(SNAT_DET_REVERSE, mp);
833   clib_memcpy(mp->out_addr, &out_addr, 4);
834   mp->out_port = htons(out_port);
835
836   S(mp);
837   W(ret);
838   return ret;
839 }
840
841 /* 
842  * List of messages that the api test plugin sends,
843  * and that the data plane plugin processes
844  */
845 #define foreach_vpe_api_msg                                      \
846 _(snat_add_address_range, "<start-addr> [- <end-addr] [del]")    \
847 _(snat_interface_add_del_feature,                                \
848   "<intfc> | sw_if_index <id> [in] [out] [del]")                 \
849 _(snat_add_static_mapping, "local_addr <ip> (external_addr <ip>" \
850   " | external_if <intfc> | external_sw_if_ndex <id>) "          \
851   "[local_port <n>] [external_port <n>] [vrf <table-id>] [del] " \
852   "protocol <n>")                                                \
853 _(snat_set_workers, "<wokrers_bitmap>")                          \
854 _(snat_static_mapping_dump, "")                                  \
855 _(snat_show_config, "")                                          \
856 _(snat_address_dump, "")                                         \
857 _(snat_interface_dump, "")                                       \
858 _(snat_worker_dump, "")                                          \
859 _(snat_add_del_interface_addr,                                   \
860   "<intfc> | sw_if_index <id> [del]")                            \
861 _(snat_interface_addr_dump, "")                                  \
862 _(snat_ipfix_enable_disable, "[domain <id>] [src_port <n>] "     \
863   "[disable]")                                                   \
864 _(snat_user_dump, "")                                            \
865 _(snat_user_session_dump, "ip_address <ip> vrf_id <table-id>")   \
866 _(snat_add_det_map, "in <in_addr>/<in_plen> out "                \
867   "<out_addr>/<out_plen> [del]")                                 \
868 _(snat_det_forward, "<in_addr>")                                 \
869 _(snat_det_reverse, "<out_addr> <out_port>")
870
871 static void 
872 snat_vat_api_hookup (vat_main_t *vam)
873 {
874   snat_test_main_t * sm __attribute__((unused)) = &snat_test_main;
875   /* Hook up handlers for replies from the data plane plug-in */
876 #define _(N,n)                                                  \
877   vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),       \
878                           #n,                                   \
879                           vl_api_##n##_t_handler,               \
880                           vl_noop_handler,                      \
881                           vl_api_##n##_t_endian,                \
882                           vl_api_##n##_t_print,                 \
883                           sizeof(vl_api_##n##_t), 1); 
884   foreach_vpe_api_reply_msg;
885 #undef _
886
887   /* API messages we can send */
888 #define _(n,h)                                          \
889   hash_set_mem (vam->function_by_name, #n, api_##n);
890   foreach_vpe_api_msg;
891 #undef _    
892     
893   /* Help strings */
894 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
895   foreach_vpe_api_msg;
896 #undef _
897 }
898
899 clib_error_t * vat_plugin_register (vat_main_t *vam)
900 {
901   snat_test_main_t * sm = &snat_test_main;
902   u8 * name;
903
904   sm->vat_main = vam;
905
906   /* Ask the vpp engine for the first assigned message-id */
907   name = format (0, "snat_%08x%c", api_version, 0);
908   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
909
910   if (sm->msg_id_base != (u16) ~0)
911     snat_vat_api_hookup (vam);
912   
913   vec_free(name);
914   
915   return 0;
916 }