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