NAT: Remove old SNAT API (VPP-1070)
[vpp.git] / src / plugins / nat / nat_test.c
1
2 /*
3  * nat.c - skeleton vpp-api-test plug-in
4  *
5  * Copyright (c) <current-year> <your-organization>
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #include <vat/vat.h>
19 #include <vlibapi/api.h>
20 #include <vlibmemory/api.h>
21
22 #include <vppinfra/error.h>
23 #include <vnet/ip/ip.h>
24 #include <nat/nat.h>
25
26 #define __plugin_msg_base snat_test_main.msg_id_base
27 #include <vlibapi/vat_helper_macros.h>
28
29 uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
30
31 /* Declare message IDs */
32 #include <nat/nat_msg_enum.h>
33
34 /* define message structures */
35 #define vl_typedefs
36 #include <nat/nat_all_api_h.h>
37 #undef vl_typedefs
38
39 /* declare message handlers for each api */
40
41 #define vl_endianfun             /* define message structures */
42 #include <nat/nat_all_api_h.h>
43 #undef vl_endianfun
44
45 /* instantiate all the print functions we know about */
46 #define vl_print(handle, ...)
47 #define vl_printfun
48 #include <nat/nat_all_api_h.h>
49 #undef vl_printfun
50
51 /* Get the API version number. */
52 #define vl_api_version(n,v) static u32 api_version=(v);
53 #include <nat/nat_all_api_h.h>
54 #undef vl_api_version
55
56 typedef struct {
57     /* API message ID base */
58     u16 msg_id_base;
59     vat_main_t *vat_main;
60 } snat_test_main_t;
61
62 snat_test_main_t snat_test_main;
63
64 #define foreach_standard_reply_retval_handler    \
65 _(nat44_add_del_address_range_reply)             \
66 _(nat44_interface_add_del_feature_reply)         \
67 _(nat44_add_del_static_mapping_reply)            \
68 _(nat_set_workers_reply)                         \
69 _(nat44_add_del_interface_addr_reply)            \
70 _(nat_ipfix_enable_disable_reply)                \
71 _(nat_det_add_del_map_reply)                     \
72 _(nat_det_set_timeouts_reply)                    \
73 _(nat_det_close_session_out_reply)               \
74 _(nat_det_close_session_in_reply)
75
76 #define _(n)                                            \
77     static void vl_api_##n##_t_handler                  \
78     (vl_api_##n##_t * mp)                               \
79     {                                                   \
80         vat_main_t * vam = snat_test_main.vat_main;   \
81         i32 retval = ntohl(mp->retval);                 \
82         if (vam->async_mode) {                          \
83             vam->async_errors += (retval < 0);          \
84         } else {                                        \
85             vam->retval = retval;                       \
86             vam->result_ready = 1;                      \
87         }                                               \
88     }
89 foreach_standard_reply_retval_handler;
90 #undef _
91
92 /*
93  * Table of message reply handlers, must include boilerplate handlers
94  * we just generated
95  */
96 #define foreach_vpe_api_reply_msg                               \
97 _(NAT44_ADD_DEL_ADDRESS_RANGE_REPLY,                            \
98   nat44_add_del_address_range_reply)                            \
99 _(NAT44_INTERFACE_ADD_DEL_FEATURE_REPLY,                        \
100   nat44_interface_add_del_feature_reply)                        \
101 _(NAT44_ADD_DEL_STATIC_MAPPING_REPLY,                           \
102   nat44_add_del_static_mapping_reply)                           \
103 _(NAT_CONTROL_PING_REPLY, nat_control_ping_reply)               \
104 _(NAT44_STATIC_MAPPING_DETAILS, nat44_static_mapping_details)   \
105 _(NAT_SHOW_CONFIG_REPLY, nat_show_config_reply)                 \
106 _(NAT44_ADDRESS_DETAILS, nat44_address_details)                 \
107 _(NAT44_INTERFACE_DETAILS, nat44_interface_details)             \
108 _(NAT_SET_WORKERS_REPLY, nat_set_workers_reply)                 \
109 _(NAT_WORKER_DETAILS, nat_worker_details)                       \
110 _(NAT44_ADD_DEL_INTERFACE_ADDR_REPLY,                           \
111   nat44_add_del_interface_addr_reply)                           \
112 _(NAT44_INTERFACE_ADDR_DETAILS, nat44_interface_addr_details)   \
113 _(NAT_IPFIX_ENABLE_DISABLE_REPLY,                               \
114   nat_ipfix_enable_disable_reply)                               \
115 _(NAT44_USER_DETAILS, nat44_user_details)                       \
116 _(NAT44_USER_SESSION_DETAILS, nat44_user_session_details)       \
117 _(NAT_DET_ADD_DEL_MAP_REPLY, nat_det_add_del_map_reply)         \
118 _(NAT_DET_FORWARD_REPLY, nat_det_forward_reply)                 \
119 _(NAT_DET_REVERSE_REPLY, nat_det_reverse_reply)                 \
120 _(NAT_DET_MAP_DETAILS, nat_det_map_details)                     \
121 _(NAT_DET_SET_TIMEOUTS_REPLY, nat_det_set_timeouts_reply)       \
122 _(NAT_DET_GET_TIMEOUTS_REPLY, nat_det_get_timeouts_reply)       \
123 _(NAT_DET_CLOSE_SESSION_OUT_REPLY,                              \
124   nat_det_close_session_out_reply)                              \
125 _(NAT_DET_CLOSE_SESSION_IN_REPLY,                               \
126   nat_det_close_session_in_reply)                               \
127 _(NAT_DET_SESSION_DETAILS, nat_det_session_details)
128
129 static int api_nat44_add_del_address_range (vat_main_t * vam)
130 {
131   unformat_input_t * i = vam->input;
132   ip4_address_t start_addr, end_addr;
133   u32 start_host_order, end_host_order;
134   vl_api_nat44_add_del_address_range_t * mp;
135   u8 is_add = 1;
136   int count;
137   int ret;
138
139   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
140     {
141       if (unformat (i, "%U - %U",
142                     unformat_ip4_address, &start_addr,
143                     unformat_ip4_address, &end_addr))
144         ;
145       else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
146         end_addr = start_addr;
147       else if (unformat (i, "del"))
148         is_add = 0;
149       else
150         {
151           clib_warning("unknown input '%U'", format_unformat_error, i);
152           return -99;
153         }
154     }
155
156   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
157   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
158
159   if (end_host_order < start_host_order)
160     {
161       errmsg ("end address less than start address\n");
162       return -99;
163     }
164
165   count = (end_host_order - start_host_order) + 1;
166
167   if (count > 1024)
168     {
169     errmsg ("%U - %U, %d addresses...\n",
170            format_ip4_address, &start_addr,
171            format_ip4_address, &end_addr,
172            count);
173     }
174
175   M(NAT44_ADD_DEL_ADDRESS_RANGE, mp);
176
177   memcpy (mp->first_ip_address, &start_addr, 4);
178   memcpy (mp->last_ip_address, &end_addr, 4);
179   mp->is_add = is_add;
180
181   S(mp);
182   W (ret);
183   return ret;
184 }
185
186 static int api_nat44_interface_add_del_feature (vat_main_t * vam)
187 {
188   unformat_input_t * i = vam->input;
189   vl_api_nat44_interface_add_del_feature_t * mp;
190   u32 sw_if_index;
191   u8 sw_if_index_set = 0;
192   u8 is_inside = 1;
193   u8 is_add = 1;
194   int ret;
195
196   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
197     {
198       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
199         sw_if_index_set = 1;
200       else if (unformat (i, "sw_if_index %d", &sw_if_index))
201         sw_if_index_set = 1;
202       else if (unformat (i, "out"))
203         is_inside = 0;
204       else if (unformat (i, "in"))
205         is_inside = 1;
206       else if (unformat (i, "del"))
207         is_add = 0;
208       else
209         {
210           clib_warning("unknown input '%U'", format_unformat_error, i);
211           return -99;
212         }
213     }
214
215   if (sw_if_index_set == 0)
216     {
217       errmsg ("interface / sw_if_index required\n");
218       return -99;
219     }
220
221   M(NAT44_INTERFACE_ADD_DEL_FEATURE, mp);
222   mp->sw_if_index = ntohl(sw_if_index);
223   mp->is_add = is_add;
224   mp->is_inside = is_inside;
225
226   S(mp);
227   W (ret);
228   return ret;
229 }
230
231 static int api_nat44_add_del_static_mapping(vat_main_t * vam)
232 {
233   unformat_input_t * i = vam->input;
234   vl_api_nat44_add_del_static_mapping_t * mp;
235   u8 external_addr_set = 0;
236   u8 local_addr_set = 0;
237   u8 is_add = 1;
238   u8 addr_only = 1;
239   ip4_address_t local_addr, external_addr;
240   u32 local_port = 0, external_port = 0, vrf_id = ~0;
241   u32 sw_if_index = ~0;
242   u8 sw_if_index_set = 0;
243   u32 proto = ~0;
244   u8 proto_set = 0;
245   int ret;
246
247   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
248     {
249       if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr))
250         local_addr_set = 1;
251       else if (unformat (i, "external_addr %U", unformat_ip4_address,
252                          &external_addr))
253         external_addr_set = 1;
254       else if (unformat (i, "local_port %u", &local_port))
255         addr_only = 0;
256       else if (unformat (i, "external_port %u", &external_port))
257         addr_only = 0;
258       else if (unformat (i, "external_if %U", unformat_sw_if_index, vam,
259                          &sw_if_index))
260         sw_if_index_set = 1;
261       else if (unformat (i, "external_sw_if_index %d", &sw_if_index))
262         sw_if_index_set = 1;
263       else if (unformat (i, "vrf %u", &vrf_id))
264         ;
265       else if (unformat (i, "protocol %u", &proto))
266         proto_set = 1;
267       else if (unformat (i, "del"))
268         is_add = 0;
269       else
270         {
271           clib_warning("unknown input '%U'", format_unformat_error, i);
272           return -99;
273         }
274     }
275
276   if (!addr_only && !proto_set)
277     {
278       errmsg ("protocol required\n");
279       return -99;
280     }
281
282   if (!local_addr_set)
283     {
284       errmsg ("local addr required\n");
285       return -99;
286     }
287   if (!external_addr_set && !sw_if_index_set)
288     {
289       errmsg ("external addr or interface required\n");
290       return -99;
291     }
292
293   M(NAT44_ADD_DEL_STATIC_MAPPING, mp);
294   mp->is_add = is_add;
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_nat_control_ping_reply_t_handler
310   (vl_api_nat_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_nat44_static_mapping_details_t_handler
326   (vl_api_nat44_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_nat44_static_mapping_dump(vat_main_t * vam)
363 {
364   vl_api_nat44_static_mapping_dump_t * mp;
365   vl_api_nat_control_ping_t *mp_ping;
366   int ret;
367
368   if (vam->json_output)
369     {
370       clib_warning ("JSON output not supported for nat44_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(NAT44_STATIC_MAPPING_DUMP, mp);
379   S(mp);
380
381   /* Use a control ping for synchronization */
382   M(NAT_CONTROL_PING, mp_ping);
383   S(mp_ping);
384
385   W (ret);
386   return ret;
387 }
388
389 static void vl_api_nat_show_config_reply_t_handler
390   (vl_api_nat_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_nat_show_config(vat_main_t * vam)
421 {
422   vl_api_nat_show_config_t * mp;
423   int ret;
424
425   if (vam->json_output)
426     {
427       clib_warning ("JSON output not supported for nat_show_config");
428       return -99;
429     }
430
431   M(NAT_SHOW_CONFIG, mp);
432   S(mp);
433   W (ret);
434   return ret;
435 }
436
437 static void vl_api_nat44_address_details_t_handler
438   (vl_api_nat44_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_nat44_address_dump(vat_main_t * vam)
447 {
448   vl_api_nat44_address_dump_t * mp;
449   vl_api_nat_control_ping_t *mp_ping;
450   int ret;
451
452   if (vam->json_output)
453     {
454       clib_warning ("JSON output not supported for nat44_address_dump");
455       return -99;
456     }
457
458   M(NAT44_ADDRESS_DUMP, mp);
459   S(mp);
460
461   /* Use a control ping for synchronization */
462   M(NAT_CONTROL_PING, mp_ping);
463   S(mp_ping);
464
465   W (ret);
466   return ret;
467 }
468
469 static void vl_api_nat44_interface_details_t_handler
470   (vl_api_nat44_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_nat44_interface_dump(vat_main_t * vam)
480 {
481   vl_api_nat44_interface_dump_t * mp;
482   vl_api_nat_control_ping_t *mp_ping;
483   int ret;
484
485   if (vam->json_output)
486     {
487       clib_warning ("JSON output not supported for nat44_address_dump");
488       return -99;
489     }
490
491   M(NAT44_INTERFACE_DUMP, mp);
492   S(mp);
493
494   /* Use a control ping for synchronization */
495   M(NAT_CONTROL_PING, mp_ping);
496   S(mp_ping);
497
498   W (ret);
499   return ret;
500 }
501
502 static int api_nat_set_workers (vat_main_t * vam)
503 {
504   unformat_input_t * i = vam->input;
505   vl_api_nat_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(NAT_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_nat_worker_details_t_handler
529   (vl_api_nat_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_nat_worker_dump(vat_main_t * vam)
539 {
540   vl_api_nat_worker_dump_t * mp;
541   vl_api_nat_control_ping_t *mp_ping;
542   int ret;
543
544   if (vam->json_output)
545     {
546       clib_warning ("JSON output not supported for nat_address_dump");
547       return -99;
548     }
549
550   M(NAT_WORKER_DUMP, mp);
551   S(mp);
552
553   /* Use a control ping for synchronization */
554   M(NAT_CONTROL_PING, mp_ping);
555   S(mp_ping);
556
557   W (ret);
558   return ret;
559 }
560
561 static int api_nat44_add_del_interface_addr (vat_main_t * vam)
562 {
563   unformat_input_t * i = vam->input;
564   vl_api_nat44_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(NAT44_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_nat44_interface_addr_details_t_handler
601   (vl_api_nat44_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_nat44_interface_addr_dump(vat_main_t * vam)
610 {
611   vl_api_nat44_interface_addr_dump_t * mp;
612   vl_api_nat_control_ping_t *mp_ping;
613   int ret;
614
615   if (vam->json_output)
616     {
617       clib_warning ("JSON output not supported for nat44_address_dump");
618       return -99;
619     }
620
621   M(NAT44_INTERFACE_ADDR_DUMP, mp);
622   S(mp);
623
624   /* Use a control ping for synchronization */
625   M(NAT_CONTROL_PING, mp_ping);
626   S(mp_ping);
627
628   W (ret);
629   return ret;
630 }
631
632 static int api_nat_ipfix_enable_disable (vat_main_t * vam)
633 {
634   unformat_input_t * i = vam->input;
635   vl_api_nat_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(NAT_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_nat44_user_session_details_t_handler
667   (vl_api_nat44_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_nat44_user_session_dump(vat_main_t * vam)
681 {
682   unformat_input_t* i = vam->input;
683   vl_api_nat44_user_session_dump_t * mp;
684   vl_api_nat_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 nat44_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(NAT44_USER_SESSION_DUMP, mp);
705   S(mp);
706
707   /* Use a control ping for synchronization */
708   M(NAT_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   S(mp_ping);
713
714   W (ret);
715   return ret;
716 }
717
718 static void vl_api_nat44_user_details_t_handler
719   (vl_api_nat44_user_details_t *mp)
720 {
721   snat_test_main_t * sm = &snat_test_main;
722   vat_main_t *vam = sm->vat_main;
723
724   fformat(vam->ofp, "user with ip %U with vrf_id %d "
725                     "with %d sessions and %d static sessions\n",
726           format_ip4_address, mp->ip_address, ntohl(mp->vrf_id),
727           ntohl(mp->nsessions), ntohl(mp->nstaticsessions));
728 }
729
730 static int api_nat44_user_dump(vat_main_t * vam)
731 {
732   vl_api_nat44_user_dump_t * mp;
733   vl_api_nat_control_ping_t *mp_ping;
734   int ret;
735
736   if (vam->json_output)
737     {
738       clib_warning ("JSON output not supported for nat44_address_dump");
739       return -99;
740     }
741
742   M(NAT44_USER_DUMP, mp);
743   S(mp);
744
745   /* Use a control ping for synchronization */
746   M(NAT_CONTROL_PING, mp_ping);
747   S(mp_ping);
748
749   W (ret);
750   return ret;
751 }
752
753 static int api_nat_det_add_del_map (vat_main_t * vam)
754 {
755   unformat_input_t * i = vam->input;
756   vl_api_nat_det_add_del_map_t * mp;
757   ip4_address_t in_addr, out_addr;
758   u32 in_plen, out_plen;
759   u8 is_add = 1;
760   int ret;
761
762   if (unformat (i, "in %U/%d out %U/%d",
763                 unformat_ip4_address, &in_addr, &in_plen,
764                 unformat_ip4_address, &out_addr, &out_plen))
765     ;
766   else if (unformat (i, "del"))
767     is_add = 0;
768   else
769     {
770       clib_warning("unknown input '%U'", format_unformat_error, i);
771       return -99;
772     }
773
774   M(NAT_DET_ADD_DEL_MAP, mp);
775   clib_memcpy(mp->in_addr, &in_addr, 4);
776   mp->in_plen = in_plen;
777   clib_memcpy(mp->out_addr, &out_addr, 4);
778   mp->out_plen = out_plen;
779   mp->is_add = is_add;
780
781   S(mp);
782   W (ret);
783   return ret;
784 }
785
786 static void vl_api_nat_det_forward_reply_t_handler
787   (vl_api_nat_det_forward_reply_t *mp)
788 {
789   snat_test_main_t * sm = &snat_test_main;
790   vat_main_t *vam = sm->vat_main;
791   i32 retval = ntohl(mp->retval);
792
793   if (retval >= 0)
794   {
795     fformat (vam->ofp, "outside address %U", format_ip4_address, &mp->out_addr);
796     fformat (vam->ofp, " outside port range start %d", ntohs(mp->out_port_lo));
797     fformat (vam->ofp, " outside port range end %d\n", ntohs(mp->out_port_hi));
798   }
799
800   vam->retval = retval;
801   vam->result_ready = 1;
802 }
803
804 static int api_nat_det_forward (vat_main_t * vam)
805 {
806   unformat_input_t * i = vam->input;
807   vl_api_nat_det_forward_t * mp;
808   ip4_address_t in_addr;
809   int ret;
810
811   if (unformat (i, "%U", unformat_ip4_address, &in_addr))
812     ;
813   else
814     {
815       clib_warning("unknown input '%U'", format_unformat_error, i);
816       return -99;
817     }
818
819   M(NAT_DET_FORWARD, mp);
820   clib_memcpy(mp->in_addr, &in_addr, 4);
821
822   S(mp);
823   W(ret);
824   return ret;
825 }
826
827 static void vl_api_nat_det_reverse_reply_t_handler
828   (vl_api_nat_det_reverse_reply_t *mp)
829 {
830   snat_test_main_t * sm = &snat_test_main;
831   vat_main_t *vam = sm->vat_main;
832   i32 retval = ntohl(mp->retval);
833
834   if (retval >= 0)
835   {
836     fformat (vam->ofp, "inside address %U\n", format_ip4_address, &mp->in_addr);
837   }
838
839   vam->retval = retval;
840   vam->result_ready = 1;
841 }
842
843 static int api_nat_det_reverse (vat_main_t * vam)
844 {
845   unformat_input_t * i = vam->input;
846   vl_api_nat_det_reverse_t * mp;
847   ip4_address_t out_addr;
848   u32 out_port;
849   int ret;
850
851   if (unformat (i, "%U %d", unformat_ip4_address, &out_addr, &out_port))
852     ;
853   else
854     {
855       clib_warning("unknown input '%U'", format_unformat_error, i);
856       return -99;
857     }
858
859   M(NAT_DET_REVERSE, mp);
860   clib_memcpy(mp->out_addr, &out_addr, 4);
861   mp->out_port = htons((u16)out_port);
862
863   S(mp);
864   W(ret);
865   return ret;
866 }
867
868 static void vl_api_nat_det_map_details_t_handler
869   (vl_api_nat_det_map_details_t *mp)
870 {
871   snat_test_main_t * sm = &snat_test_main;
872   vat_main_t *vam = sm->vat_main;
873
874   fformat (vam->ofp, "Deterministic S-NAT mapping in %U/%d out %U/%d "
875                      "ports per host %d sharing ratio %d "
876                      "number of sessions %d",
877            format_ip4_address, mp->in_addr, mp->in_plen,
878            format_ip4_address, mp->out_addr, mp->out_plen,
879            ntohs(mp->ports_per_host), ntohl(mp->sharing_ratio),
880            ntohl(mp->ses_num));
881 }
882
883 static int api_nat_det_map_dump(vat_main_t * vam)
884 {
885   vl_api_nat_det_map_dump_t * mp;
886   vl_api_nat_control_ping_t *mp_ping;
887   int ret;
888
889   if (vam->json_output)
890     {
891       clib_warning ("JSON output not supported for nat_det_map_dump");
892       return -99;
893     }
894
895   M(NAT_DET_MAP_DUMP, mp);
896   S(mp);
897
898   /* Use a control ping for synchronization */
899   M(NAT_CONTROL_PING, mp_ping);
900   S(mp_ping);
901
902   W (ret);
903   return ret;
904 }
905
906 static int api_nat_det_set_timeouts (vat_main_t * vam)
907 {
908   unformat_input_t * i = vam->input;
909   vl_api_nat_det_set_timeouts_t * mp;
910   u32 udp = SNAT_UDP_TIMEOUT;
911   u32 tcp_established = SNAT_TCP_ESTABLISHED_TIMEOUT;
912   u32 tcp_transitory = SNAT_TCP_TRANSITORY_TIMEOUT;
913   u32 icmp = SNAT_ICMP_TIMEOUT;
914   int ret;
915
916   if (unformat (i, "udp %d", &udp))
917     ;
918   else if (unformat (i, "tcp_established %d", &tcp_established))
919     ;
920   else if (unformat (i, "tcp_transitory %d", &tcp_transitory))
921     ;
922   else if (unformat (i, "icmp %d", &icmp))
923     ;
924   else
925     {
926       clib_warning("unknown input '%U'", format_unformat_error, i);
927       return -99;
928     }
929
930   M(NAT_DET_SET_TIMEOUTS, mp);
931   mp->udp = htonl(udp);
932   mp->tcp_established = htonl(tcp_established);
933   mp->tcp_transitory = htonl(tcp_transitory);
934   mp->icmp = htonl(icmp);
935
936   S(mp);
937   W (ret);
938   return ret;
939 }
940
941 static void vl_api_nat_det_get_timeouts_reply_t_handler
942   (vl_api_nat_det_get_timeouts_reply_t *mp)
943 {
944   snat_test_main_t * sm = &snat_test_main;
945   vat_main_t *vam = sm->vat_main;
946   i32 retval = ntohl (mp->retval);
947
948   if (retval >= 0)
949     {
950       fformat (vam->ofp, "udp timeout: %dsec\n", ntohl (mp->udp));
951       fformat (vam->ofp, "tcp-established timeout: %dsec",
952                ntohl (mp->tcp_established));
953       fformat (vam->ofp, "tcp-transitory timeout: %dsec",
954                ntohl (mp->tcp_transitory));
955       fformat (vam->ofp, "icmp timeout: %dsec", ntohl (mp->icmp));
956     }
957   vam->retval = retval;
958   vam->result_ready = 1;
959 }
960
961 static int api_nat_det_get_timeouts(vat_main_t * vam)
962 {
963   vl_api_nat_det_get_timeouts_t * mp;
964   int ret;
965
966   if (vam->json_output)
967     {
968       clib_warning ("JSON output not supported for nat_show_config");
969       return -99;
970     }
971
972   M(NAT_DET_GET_TIMEOUTS, mp);
973   S(mp);
974   W (ret);
975   return ret;
976 }
977
978 static int api_nat_det_close_session_out (vat_main_t * vam)
979 {
980   unformat_input_t * i = vam->input;
981   vl_api_nat_det_close_session_out_t * mp;
982   ip4_address_t out_addr, ext_addr;
983   u32 out_port, ext_port;
984   int ret;
985
986   if (unformat (i, "%U:%d %U:%d",
987                 unformat_ip4_address, &out_addr, &out_port,
988                 unformat_ip4_address, &ext_addr, &ext_port))
989     ;
990   else
991     {
992       clib_warning("unknown input '%U'", format_unformat_error, i);
993       return -99;
994     }
995
996   M(NAT_DET_CLOSE_SESSION_OUT, mp);
997   clib_memcpy(mp->out_addr, &out_addr, 4);
998   mp->out_port = ntohs((u16)out_port);
999   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1000   mp->ext_port = ntohs((u16)ext_port);
1001
1002   S(mp);
1003   W (ret);
1004   return ret;
1005 }
1006
1007 static int api_nat_det_close_session_in (vat_main_t * vam)
1008 {
1009   unformat_input_t * i = vam->input;
1010   vl_api_nat_det_close_session_in_t * mp;
1011   ip4_address_t in_addr, ext_addr;
1012   u32 in_port, ext_port;
1013   int ret;
1014
1015   if (unformat (i, "%U:%d %U:%d",
1016                 unformat_ip4_address, &in_addr, &in_port,
1017                 unformat_ip4_address, &ext_addr, &ext_port))
1018     ;
1019   else
1020     {
1021       clib_warning("unknown input '%U'", format_unformat_error, i);
1022       return -99;
1023     }
1024
1025   M(NAT_DET_CLOSE_SESSION_IN, mp);
1026   clib_memcpy(mp->in_addr, &in_addr, 4);
1027   mp->in_port = ntohs((u16)in_port);
1028   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1029   mp->ext_port = ntohs((u16)ext_port);
1030
1031   S(mp);
1032   W (ret);
1033   return ret;
1034 }
1035
1036 static void vl_api_nat_det_session_details_t_handler
1037   (vl_api_nat_det_session_details_t *mp)
1038 {
1039   snat_test_main_t * sm = &snat_test_main;
1040   vat_main_t *vam = sm->vat_main;
1041
1042   fformat(vam->ofp, "deterministic session, external host address %U, "
1043                     "external host port %d, outer port %d, inside port %d",
1044           format_ip4_address, mp->ext_addr, mp->ext_port,
1045           mp->out_port, mp->in_port);
1046 }
1047
1048 static int api_nat_det_session_dump(vat_main_t * vam)
1049 {
1050   unformat_input_t* i = vam->input;
1051   vl_api_nat_det_session_dump_t * mp;
1052   vl_api_nat_control_ping_t *mp_ping;
1053   ip4_address_t user_addr;
1054   int ret;
1055
1056   if (vam->json_output)
1057     {
1058       clib_warning ("JSON output not supported for nat_det_session_dump");
1059       return -99;
1060     }
1061
1062   if (unformat (i, "user_addr %U", unformat_ip4_address, &user_addr))
1063     ;
1064   else
1065     {
1066       clib_warning ("unknown input '%U'", format_unformat_error, i);
1067       return -99;
1068     }
1069
1070   M(NAT_DET_SESSION_DUMP, mp);
1071   clib_memcpy (&mp->user_addr, &user_addr, 4);
1072   S(mp);
1073
1074   /* Use a control ping for synchronization */
1075   M(NAT_CONTROL_PING, mp_ping);
1076   S(mp_ping);
1077
1078   W (ret);
1079   return ret;
1080 }
1081
1082 /*
1083  * List of messages that the api test plugin sends,
1084  * and that the data plane plugin processes
1085  */
1086 #define foreach_vpe_api_msg                                       \
1087 _(nat44_add_del_address_range, "<start-addr> [- <end-addr] [del]")\
1088 _(nat44_interface_add_del_feature,                                \
1089   "<intfc> | sw_if_index <id> [in] [out] [del]")                  \
1090 _(nat44_add_del_static_mapping, "local_addr <ip>"                 \
1091   " (external_addr <ip> | external_if <intfc> |"                  \
1092   " external_sw_if_ndex <id>) [local_port <n>]"                   \
1093   " [external_port <n>] [vrf <table-id>] [del] protocol <n>")     \
1094 _(nat_set_workers, "<wokrers_bitmap>")                            \
1095 _(nat44_static_mapping_dump, "")                                  \
1096 _(nat_show_config, "")                                            \
1097 _(nat44_address_dump, "")                                         \
1098 _(nat44_interface_dump, "")                                       \
1099 _(nat_worker_dump, "")                                            \
1100 _(nat44_add_del_interface_addr,                                   \
1101   "<intfc> | sw_if_index <id> [del]")                             \
1102 _(nat44_interface_addr_dump, "")                                  \
1103 _(nat_ipfix_enable_disable, "[domain <id>] [src_port <n>] "       \
1104   "[disable]")                                                    \
1105 _(nat44_user_dump, "")                                            \
1106 _(nat44_user_session_dump, "ip_address <ip> vrf_id <table-id>")   \
1107 _(nat_det_add_del_map, "in <in_addr>/<in_plen> out "              \
1108   "<out_addr>/<out_plen> [del]")                                  \
1109 _(nat_det_forward, "<in_addr>")                                   \
1110 _(nat_det_reverse, "<out_addr> <out_port>")                       \
1111 _(nat_det_map_dump, "")                                           \
1112 _(nat_det_set_timeouts, "[udp <sec> | tcp_established <sec> | "   \
1113   "tcp_transitory <sec> | icmp <sec>]")                           \
1114 _(nat_det_get_timeouts, "")                                       \
1115 _(nat_det_close_session_out, "<out_addr>:<out_port> "             \
1116   "<ext_addr>:<ext_port>")                                        \
1117 _(nat_det_close_session_in, "<in_addr>:<in_port> "                \
1118   "<out_addr>:<out_port>")                                        \
1119 _(nat_det_session_dump, "ip_address <user_addr>")
1120
1121 static void
1122 snat_vat_api_hookup (vat_main_t *vam)
1123 {
1124   snat_test_main_t * sm __attribute__((unused)) = &snat_test_main;
1125   /* Hook up handlers for replies from the data plane plug-in */
1126 #define _(N,n)                                                  \
1127   vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),       \
1128                           #n,                                   \
1129                           vl_api_##n##_t_handler,               \
1130                           vl_noop_handler,                      \
1131                           vl_api_##n##_t_endian,                \
1132                           vl_api_##n##_t_print,                 \
1133                           sizeof(vl_api_##n##_t), 1);
1134   foreach_vpe_api_reply_msg;
1135 #undef _
1136
1137   /* API messages we can send */
1138 #define _(n,h)                                          \
1139   hash_set_mem (vam->function_by_name, #n, api_##n);
1140   foreach_vpe_api_msg;
1141 #undef _
1142
1143   /* Help strings */
1144 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
1145   foreach_vpe_api_msg;
1146 #undef _
1147 }
1148
1149 clib_error_t * vat_plugin_register (vat_main_t *vam)
1150 {
1151   snat_test_main_t * sm = &snat_test_main;
1152   u8 * name;
1153
1154   sm->vat_main = vam;
1155
1156   /* Ask the vpp engine for the first assigned message-id */
1157   name = format (0, "nat_%08x%c", api_version, 0);
1158   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
1159
1160   if (sm->msg_id_base != (u16) ~0)
1161     snat_vat_api_hookup (vam);
1162
1163   vec_free(name);
1164
1165   return 0;
1166 }