NAT44: add support for session timeout (VPP-1272)
[vpp.git] / src / plugins / nat / nat_test.c
1
2 /*
3  * nat.c - skeleton vpp-api-test plug-in
4  *
5  * Copyright (c) <current-year> <your-organization>
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #include <vat/vat.h>
19 #include <vlibapi/api.h>
20 #include <vlibmemory/api.h>
21
22 #include <vppinfra/error.h>
23 #include <vnet/ip/ip.h>
24 #include <nat/nat.h>
25
26 #define __plugin_msg_base snat_test_main.msg_id_base
27 #include <vlibapi/vat_helper_macros.h>
28
29 uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
30
31 /* Declare message IDs */
32 #include <nat/nat_msg_enum.h>
33
34 /* define message structures */
35 #define vl_typedefs
36 #include <nat/nat_all_api_h.h>
37 #undef vl_typedefs
38
39 /* declare message handlers for each api */
40
41 #define vl_endianfun             /* define message structures */
42 #include <nat/nat_all_api_h.h>
43 #undef vl_endianfun
44
45 /* instantiate all the print functions we know about */
46 #define vl_print(handle, ...)
47 #define vl_printfun
48 #include <nat/nat_all_api_h.h>
49 #undef vl_printfun
50
51 /* Get the API version number. */
52 #define vl_api_version(n,v) static u32 api_version=(v);
53 #include <nat/nat_all_api_h.h>
54 #undef vl_api_version
55
56 typedef struct {
57     /* API message ID base */
58     u16 msg_id_base;
59     vat_main_t *vat_main;
60 } snat_test_main_t;
61
62 snat_test_main_t snat_test_main;
63
64 #define foreach_standard_reply_retval_handler    \
65 _(nat44_add_del_address_range_reply)             \
66 _(nat44_interface_add_del_feature_reply)         \
67 _(nat44_add_del_static_mapping_reply)            \
68 _(nat_set_workers_reply)                         \
69 _(nat44_add_del_interface_addr_reply)            \
70 _(nat_ipfix_enable_disable_reply)                \
71 _(nat_det_add_del_map_reply)                     \
72 _(nat_set_timeouts_reply)                        \
73 _(nat_det_close_session_out_reply)               \
74 _(nat_det_close_session_in_reply)
75
76 #define _(n)                                            \
77     static void vl_api_##n##_t_handler                  \
78     (vl_api_##n##_t * mp)                               \
79     {                                                   \
80         vat_main_t * vam = snat_test_main.vat_main;   \
81         i32 retval = ntohl(mp->retval);                 \
82         if (vam->async_mode) {                          \
83             vam->async_errors += (retval < 0);          \
84         } else {                                        \
85             vam->retval = retval;                       \
86             vam->result_ready = 1;                      \
87         }                                               \
88     }
89 foreach_standard_reply_retval_handler;
90 #undef _
91
92 /*
93  * Table of message reply handlers, must include boilerplate handlers
94  * we just generated
95  */
96 #define foreach_vpe_api_reply_msg                               \
97 _(NAT44_ADD_DEL_ADDRESS_RANGE_REPLY,                            \
98   nat44_add_del_address_range_reply)                            \
99 _(NAT44_INTERFACE_ADD_DEL_FEATURE_REPLY,                        \
100   nat44_interface_add_del_feature_reply)                        \
101 _(NAT44_ADD_DEL_STATIC_MAPPING_REPLY,                           \
102   nat44_add_del_static_mapping_reply)                           \
103 _(NAT_CONTROL_PING_REPLY, nat_control_ping_reply)               \
104 _(NAT44_STATIC_MAPPING_DETAILS, nat44_static_mapping_details)   \
105 _(NAT_SHOW_CONFIG_REPLY, nat_show_config_reply)                 \
106 _(NAT44_ADDRESS_DETAILS, nat44_address_details)                 \
107 _(NAT44_INTERFACE_DETAILS, nat44_interface_details)             \
108 _(NAT_SET_WORKERS_REPLY, nat_set_workers_reply)                 \
109 _(NAT_WORKER_DETAILS, nat_worker_details)                       \
110 _(NAT44_ADD_DEL_INTERFACE_ADDR_REPLY,                           \
111   nat44_add_del_interface_addr_reply)                           \
112 _(NAT44_INTERFACE_ADDR_DETAILS, nat44_interface_addr_details)   \
113 _(NAT_IPFIX_ENABLE_DISABLE_REPLY,                               \
114   nat_ipfix_enable_disable_reply)                               \
115 _(NAT44_USER_DETAILS, nat44_user_details)                       \
116 _(NAT44_USER_SESSION_DETAILS, nat44_user_session_details)       \
117 _(NAT_DET_ADD_DEL_MAP_REPLY, nat_det_add_del_map_reply)         \
118 _(NAT_DET_FORWARD_REPLY, nat_det_forward_reply)                 \
119 _(NAT_DET_REVERSE_REPLY, nat_det_reverse_reply)                 \
120 _(NAT_DET_MAP_DETAILS, nat_det_map_details)                     \
121 _(NAT_SET_TIMEOUTS_REPLY, nat_set_timeouts_reply)               \
122 _(NAT_GET_TIMEOUTS_REPLY, nat_get_timeouts_reply)               \
123 _(NAT_DET_CLOSE_SESSION_OUT_REPLY,                              \
124   nat_det_close_session_out_reply)                              \
125 _(NAT_DET_CLOSE_SESSION_IN_REPLY,                               \
126   nat_det_close_session_in_reply)                               \
127 _(NAT_DET_SESSION_DETAILS, nat_det_session_details)
128
129 static int api_nat44_add_del_address_range (vat_main_t * vam)
130 {
131   unformat_input_t * i = vam->input;
132   ip4_address_t start_addr, end_addr;
133   u32 start_host_order, end_host_order;
134   vl_api_nat44_add_del_address_range_t * mp;
135   u8 is_add = 1;
136   int count;
137   int ret;
138
139   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
140     {
141       if (unformat (i, "%U - %U",
142                     unformat_ip4_address, &start_addr,
143                     unformat_ip4_address, &end_addr))
144         ;
145       else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
146         end_addr = start_addr;
147       else if (unformat (i, "del"))
148         is_add = 0;
149       else
150         {
151           clib_warning("unknown input '%U'", format_unformat_error, i);
152           return -99;
153         }
154     }
155
156   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
157   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
158
159   if (end_host_order < start_host_order)
160     {
161       errmsg ("end address less than start address\n");
162       return -99;
163     }
164
165   count = (end_host_order - start_host_order) + 1;
166
167   if (count > 1024)
168     {
169     errmsg ("%U - %U, %d addresses...\n",
170            format_ip4_address, &start_addr,
171            format_ip4_address, &end_addr,
172            count);
173     }
174
175   M(NAT44_ADD_DEL_ADDRESS_RANGE, mp);
176
177   memcpy (mp->first_ip_address, &start_addr, 4);
178   memcpy (mp->last_ip_address, &end_addr, 4);
179   mp->is_add = is_add;
180
181   S(mp);
182   W (ret);
183   return ret;
184 }
185
186 static int api_nat44_interface_add_del_feature (vat_main_t * vam)
187 {
188   unformat_input_t * i = vam->input;
189   vl_api_nat44_interface_add_del_feature_t * mp;
190   u32 sw_if_index;
191   u8 sw_if_index_set = 0;
192   u8 is_inside = 1;
193   u8 is_add = 1;
194   int ret;
195
196   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
197     {
198       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
199         sw_if_index_set = 1;
200       else if (unformat (i, "sw_if_index %d", &sw_if_index))
201         sw_if_index_set = 1;
202       else if (unformat (i, "out"))
203         is_inside = 0;
204       else if (unformat (i, "in"))
205         is_inside = 1;
206       else if (unformat (i, "del"))
207         is_add = 0;
208       else
209         {
210           clib_warning("unknown input '%U'", format_unformat_error, i);
211           return -99;
212         }
213     }
214
215   if (sw_if_index_set == 0)
216     {
217       errmsg ("interface / sw_if_index required\n");
218       return -99;
219     }
220
221   M(NAT44_INTERFACE_ADD_DEL_FEATURE, mp);
222   mp->sw_if_index = ntohl(sw_if_index);
223   mp->is_add = is_add;
224   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 %lld\n",
674           mp->is_static ? "static" : "dynamic",
675           format_ip4_address, mp->inside_ip_address, ntohs(mp->inside_port),
676           format_ip4_address, mp->outside_ip_address, ntohs(mp->outside_port),
677           ntohs(mp->protocol), ntohl(mp->total_pkts),
678           clib_net_to_host_u64(mp->total_bytes));
679 }
680
681 static int api_nat44_user_session_dump(vat_main_t * vam)
682 {
683   unformat_input_t* i = vam->input;
684   vl_api_nat44_user_session_dump_t * mp;
685   vl_api_nat_control_ping_t *mp_ping;
686   ip4_address_t addr;
687   u32 vrf_id = ~0;
688   int ret;
689
690   if (vam->json_output)
691     {
692       clib_warning ("JSON output not supported for nat44_address_dump");
693       return -99;
694     }
695
696   if (unformat (i, "ip_address %U vrf_id %d",
697                 unformat_ip4_address, &addr, &vrf_id))
698     ;
699   else
700     {
701       clib_warning("unknown input '%U'", format_unformat_error, i);
702       return -99;
703     }
704
705   M(NAT44_USER_SESSION_DUMP, mp);
706   S(mp);
707
708   /* Use a control ping for synchronization */
709   M(NAT_CONTROL_PING, mp_ping);
710   memset(mp->ip_address, 0, 16);
711   clib_memcpy(mp->ip_address, &addr, 4);
712   mp->vrf_id = htonl(vrf_id);
713   S(mp_ping);
714
715   W (ret);
716   return ret;
717 }
718
719 static void vl_api_nat44_user_details_t_handler
720   (vl_api_nat44_user_details_t *mp)
721 {
722   snat_test_main_t * sm = &snat_test_main;
723   vat_main_t *vam = sm->vat_main;
724
725   fformat(vam->ofp, "user with ip %U with vrf_id %d "
726                     "with %d sessions and %d static sessions\n",
727           format_ip4_address, mp->ip_address, ntohl(mp->vrf_id),
728           ntohl(mp->nsessions), ntohl(mp->nstaticsessions));
729 }
730
731 static int api_nat44_user_dump(vat_main_t * vam)
732 {
733   vl_api_nat44_user_dump_t * mp;
734   vl_api_nat_control_ping_t *mp_ping;
735   int ret;
736
737   if (vam->json_output)
738     {
739       clib_warning ("JSON output not supported for nat44_address_dump");
740       return -99;
741     }
742
743   M(NAT44_USER_DUMP, mp);
744   S(mp);
745
746   /* Use a control ping for synchronization */
747   M(NAT_CONTROL_PING, mp_ping);
748   S(mp_ping);
749
750   W (ret);
751   return ret;
752 }
753
754 static int api_nat_det_add_del_map (vat_main_t * vam)
755 {
756   unformat_input_t * i = vam->input;
757   vl_api_nat_det_add_del_map_t * mp;
758   ip4_address_t in_addr, out_addr;
759   u32 in_plen, out_plen;
760   u8 is_add = 1;
761   int ret;
762
763   if (unformat (i, "in %U/%d out %U/%d",
764                 unformat_ip4_address, &in_addr, &in_plen,
765                 unformat_ip4_address, &out_addr, &out_plen))
766     ;
767   else if (unformat (i, "del"))
768     is_add = 0;
769   else
770     {
771       clib_warning("unknown input '%U'", format_unformat_error, i);
772       return -99;
773     }
774
775   M(NAT_DET_ADD_DEL_MAP, mp);
776   clib_memcpy(mp->in_addr, &in_addr, 4);
777   mp->in_plen = in_plen;
778   clib_memcpy(mp->out_addr, &out_addr, 4);
779   mp->out_plen = out_plen;
780   mp->is_add = is_add;
781
782   S(mp);
783   W (ret);
784   return ret;
785 }
786
787 static void vl_api_nat_det_forward_reply_t_handler
788   (vl_api_nat_det_forward_reply_t *mp)
789 {
790   snat_test_main_t * sm = &snat_test_main;
791   vat_main_t *vam = sm->vat_main;
792   i32 retval = ntohl(mp->retval);
793
794   if (retval >= 0)
795   {
796     fformat (vam->ofp, "outside address %U", format_ip4_address, &mp->out_addr);
797     fformat (vam->ofp, " outside port range start %d", ntohs(mp->out_port_lo));
798     fformat (vam->ofp, " outside port range end %d\n", ntohs(mp->out_port_hi));
799   }
800
801   vam->retval = retval;
802   vam->result_ready = 1;
803 }
804
805 static int api_nat_det_forward (vat_main_t * vam)
806 {
807   unformat_input_t * i = vam->input;
808   vl_api_nat_det_forward_t * mp;
809   ip4_address_t in_addr;
810   int ret;
811
812   if (unformat (i, "%U", unformat_ip4_address, &in_addr))
813     ;
814   else
815     {
816       clib_warning("unknown input '%U'", format_unformat_error, i);
817       return -99;
818     }
819
820   M(NAT_DET_FORWARD, mp);
821   clib_memcpy(mp->in_addr, &in_addr, 4);
822
823   S(mp);
824   W(ret);
825   return ret;
826 }
827
828 static void vl_api_nat_det_reverse_reply_t_handler
829   (vl_api_nat_det_reverse_reply_t *mp)
830 {
831   snat_test_main_t * sm = &snat_test_main;
832   vat_main_t *vam = sm->vat_main;
833   i32 retval = ntohl(mp->retval);
834
835   if (retval >= 0)
836   {
837     fformat (vam->ofp, "inside address %U\n", format_ip4_address, &mp->in_addr);
838   }
839
840   vam->retval = retval;
841   vam->result_ready = 1;
842 }
843
844 static int api_nat_det_reverse (vat_main_t * vam)
845 {
846   unformat_input_t * i = vam->input;
847   vl_api_nat_det_reverse_t * mp;
848   ip4_address_t out_addr;
849   u32 out_port;
850   int ret;
851
852   if (unformat (i, "%U %d", unformat_ip4_address, &out_addr, &out_port))
853     ;
854   else
855     {
856       clib_warning("unknown input '%U'", format_unformat_error, i);
857       return -99;
858     }
859
860   M(NAT_DET_REVERSE, mp);
861   clib_memcpy(mp->out_addr, &out_addr, 4);
862   mp->out_port = htons((u16)out_port);
863
864   S(mp);
865   W(ret);
866   return ret;
867 }
868
869 static void vl_api_nat_det_map_details_t_handler
870   (vl_api_nat_det_map_details_t *mp)
871 {
872   snat_test_main_t * sm = &snat_test_main;
873   vat_main_t *vam = sm->vat_main;
874
875   fformat (vam->ofp, "Deterministic S-NAT mapping in %U/%d out %U/%d "
876                      "ports per host %d sharing ratio %d "
877                      "number of sessions %d",
878            format_ip4_address, mp->in_addr, mp->in_plen,
879            format_ip4_address, mp->out_addr, mp->out_plen,
880            ntohs(mp->ports_per_host), ntohl(mp->sharing_ratio),
881            ntohl(mp->ses_num));
882 }
883
884 static int api_nat_det_map_dump(vat_main_t * vam)
885 {
886   vl_api_nat_det_map_dump_t * mp;
887   vl_api_nat_control_ping_t *mp_ping;
888   int ret;
889
890   if (vam->json_output)
891     {
892       clib_warning ("JSON output not supported for nat_det_map_dump");
893       return -99;
894     }
895
896   M(NAT_DET_MAP_DUMP, mp);
897   S(mp);
898
899   /* Use a control ping for synchronization */
900   M(NAT_CONTROL_PING, mp_ping);
901   S(mp_ping);
902
903   W (ret);
904   return ret;
905 }
906
907 static int api_nat_set_timeouts (vat_main_t * vam)
908 {
909   unformat_input_t * i = vam->input;
910   vl_api_nat_set_timeouts_t * mp;
911   u32 udp = SNAT_UDP_TIMEOUT;
912   u32 tcp_established = SNAT_TCP_ESTABLISHED_TIMEOUT;
913   u32 tcp_transitory = SNAT_TCP_TRANSITORY_TIMEOUT;
914   u32 icmp = SNAT_ICMP_TIMEOUT;
915   int ret;
916
917   if (unformat (i, "udp %d", &udp))
918     ;
919   else if (unformat (i, "tcp_established %d", &tcp_established))
920     ;
921   else if (unformat (i, "tcp_transitory %d", &tcp_transitory))
922     ;
923   else if (unformat (i, "icmp %d", &icmp))
924     ;
925   else
926     {
927       clib_warning("unknown input '%U'", format_unformat_error, i);
928       return -99;
929     }
930
931   M(NAT_SET_TIMEOUTS, mp);
932   mp->udp = htonl(udp);
933   mp->tcp_established = htonl(tcp_established);
934   mp->tcp_transitory = htonl(tcp_transitory);
935   mp->icmp = htonl(icmp);
936
937   S(mp);
938   W (ret);
939   return ret;
940 }
941
942 static void vl_api_nat_get_timeouts_reply_t_handler
943   (vl_api_nat_get_timeouts_reply_t *mp)
944 {
945   snat_test_main_t * sm = &snat_test_main;
946   vat_main_t *vam = sm->vat_main;
947   i32 retval = ntohl (mp->retval);
948
949   if (retval >= 0)
950     {
951       fformat (vam->ofp, "udp timeout: %dsec\n", ntohl (mp->udp));
952       fformat (vam->ofp, "tcp-established timeout: %dsec",
953                ntohl (mp->tcp_established));
954       fformat (vam->ofp, "tcp-transitory timeout: %dsec",
955                ntohl (mp->tcp_transitory));
956       fformat (vam->ofp, "icmp timeout: %dsec", ntohl (mp->icmp));
957     }
958   vam->retval = retval;
959   vam->result_ready = 1;
960 }
961
962 static int api_nat_get_timeouts(vat_main_t * vam)
963 {
964   vl_api_nat_get_timeouts_t * mp;
965   int ret;
966
967   if (vam->json_output)
968     {
969       clib_warning ("JSON output not supported for nat_get_timeouts");
970       return -99;
971     }
972
973   M(NAT_GET_TIMEOUTS, mp);
974   S(mp);
975   W (ret);
976   return ret;
977 }
978
979 static int api_nat_det_close_session_out (vat_main_t * vam)
980 {
981   unformat_input_t * i = vam->input;
982   vl_api_nat_det_close_session_out_t * mp;
983   ip4_address_t out_addr, ext_addr;
984   u32 out_port, ext_port;
985   int ret;
986
987   if (unformat (i, "%U:%d %U:%d",
988                 unformat_ip4_address, &out_addr, &out_port,
989                 unformat_ip4_address, &ext_addr, &ext_port))
990     ;
991   else
992     {
993       clib_warning("unknown input '%U'", format_unformat_error, i);
994       return -99;
995     }
996
997   M(NAT_DET_CLOSE_SESSION_OUT, mp);
998   clib_memcpy(mp->out_addr, &out_addr, 4);
999   mp->out_port = ntohs((u16)out_port);
1000   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1001   mp->ext_port = ntohs((u16)ext_port);
1002
1003   S(mp);
1004   W (ret);
1005   return ret;
1006 }
1007
1008 static int api_nat_det_close_session_in (vat_main_t * vam)
1009 {
1010   unformat_input_t * i = vam->input;
1011   vl_api_nat_det_close_session_in_t * mp;
1012   ip4_address_t in_addr, ext_addr;
1013   u32 in_port, ext_port;
1014   int ret;
1015
1016   if (unformat (i, "%U:%d %U:%d",
1017                 unformat_ip4_address, &in_addr, &in_port,
1018                 unformat_ip4_address, &ext_addr, &ext_port))
1019     ;
1020   else
1021     {
1022       clib_warning("unknown input '%U'", format_unformat_error, i);
1023       return -99;
1024     }
1025
1026   M(NAT_DET_CLOSE_SESSION_IN, mp);
1027   clib_memcpy(mp->in_addr, &in_addr, 4);
1028   mp->in_port = ntohs((u16)in_port);
1029   clib_memcpy(mp->ext_addr, &ext_addr, 4);
1030   mp->ext_port = ntohs((u16)ext_port);
1031
1032   S(mp);
1033   W (ret);
1034   return ret;
1035 }
1036
1037 static void vl_api_nat_det_session_details_t_handler
1038   (vl_api_nat_det_session_details_t *mp)
1039 {
1040   snat_test_main_t * sm = &snat_test_main;
1041   vat_main_t *vam = sm->vat_main;
1042
1043   fformat(vam->ofp, "deterministic session, external host address %U, "
1044                     "external host port %d, outer port %d, inside port %d",
1045           format_ip4_address, mp->ext_addr, mp->ext_port,
1046           mp->out_port, mp->in_port);
1047 }
1048
1049 static int api_nat_det_session_dump(vat_main_t * vam)
1050 {
1051   unformat_input_t* i = vam->input;
1052   vl_api_nat_det_session_dump_t * mp;
1053   vl_api_nat_control_ping_t *mp_ping;
1054   ip4_address_t user_addr;
1055   int ret;
1056
1057   if (vam->json_output)
1058     {
1059       clib_warning ("JSON output not supported for nat_det_session_dump");
1060       return -99;
1061     }
1062
1063   if (unformat (i, "user_addr %U", unformat_ip4_address, &user_addr))
1064     ;
1065   else
1066     {
1067       clib_warning ("unknown input '%U'", format_unformat_error, i);
1068       return -99;
1069     }
1070
1071   M(NAT_DET_SESSION_DUMP, mp);
1072   clib_memcpy (&mp->user_addr, &user_addr, 4);
1073   S(mp);
1074
1075   /* Use a control ping for synchronization */
1076   M(NAT_CONTROL_PING, mp_ping);
1077   S(mp_ping);
1078
1079   W (ret);
1080   return ret;
1081 }
1082
1083 /*
1084  * List of messages that the api test plugin sends,
1085  * and that the data plane plugin processes
1086  */
1087 #define foreach_vpe_api_msg                                       \
1088 _(nat44_add_del_address_range, "<start-addr> [- <end-addr] [del]")\
1089 _(nat44_interface_add_del_feature,                                \
1090   "<intfc> | sw_if_index <id> [in] [out] [del]")                  \
1091 _(nat44_add_del_static_mapping, "local_addr <ip>"                 \
1092   " (external_addr <ip> | external_if <intfc> |"                  \
1093   " external_sw_if_ndex <id>) [local_port <n>]"                   \
1094   " [external_port <n>] [vrf <table-id>] [del] protocol <n>")     \
1095 _(nat_set_workers, "<wokrers_bitmap>")                            \
1096 _(nat44_static_mapping_dump, "")                                  \
1097 _(nat_show_config, "")                                            \
1098 _(nat44_address_dump, "")                                         \
1099 _(nat44_interface_dump, "")                                       \
1100 _(nat_worker_dump, "")                                            \
1101 _(nat44_add_del_interface_addr,                                   \
1102   "<intfc> | sw_if_index <id> [del]")                             \
1103 _(nat44_interface_addr_dump, "")                                  \
1104 _(nat_ipfix_enable_disable, "[domain <id>] [src_port <n>] "       \
1105   "[disable]")                                                    \
1106 _(nat44_user_dump, "")                                            \
1107 _(nat44_user_session_dump, "ip_address <ip> vrf_id <table-id>")   \
1108 _(nat_det_add_del_map, "in <in_addr>/<in_plen> out "              \
1109   "<out_addr>/<out_plen> [del]")                                  \
1110 _(nat_det_forward, "<in_addr>")                                   \
1111 _(nat_det_reverse, "<out_addr> <out_port>")                       \
1112 _(nat_det_map_dump, "")                                           \
1113 _(nat_set_timeouts, "[udp <sec> | tcp_established <sec> | "       \
1114   "tcp_transitory <sec> | icmp <sec>]")                           \
1115 _(nat_get_timeouts, "")                                           \
1116 _(nat_det_close_session_out, "<out_addr>:<out_port> "             \
1117   "<ext_addr>:<ext_port>")                                        \
1118 _(nat_det_close_session_in, "<in_addr>:<in_port> "                \
1119   "<out_addr>:<out_port>")                                        \
1120 _(nat_det_session_dump, "ip_address <user_addr>")
1121
1122 static void
1123 snat_vat_api_hookup (vat_main_t *vam)
1124 {
1125   snat_test_main_t * sm __attribute__((unused)) = &snat_test_main;
1126   /* Hook up handlers for replies from the data plane plug-in */
1127 #define _(N,n)                                                  \
1128   vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),       \
1129                           #n,                                   \
1130                           vl_api_##n##_t_handler,               \
1131                           vl_noop_handler,                      \
1132                           vl_api_##n##_t_endian,                \
1133                           vl_api_##n##_t_print,                 \
1134                           sizeof(vl_api_##n##_t), 1);
1135   foreach_vpe_api_reply_msg;
1136 #undef _
1137
1138   /* API messages we can send */
1139 #define _(n,h)                                          \
1140   hash_set_mem (vam->function_by_name, #n, api_##n);
1141   foreach_vpe_api_msg;
1142 #undef _
1143
1144   /* Help strings */
1145 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
1146   foreach_vpe_api_msg;
1147 #undef _
1148 }
1149
1150 clib_error_t * vat_plugin_register (vat_main_t *vam)
1151 {
1152   snat_test_main_t * sm = &snat_test_main;
1153   u8 * name;
1154
1155   sm->vat_main = vam;
1156
1157   /* Ask the vpp engine for the first assigned message-id */
1158   name = format (0, "nat_%08x%c", api_version, 0);
1159   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
1160
1161   if (sm->msg_id_base != (u16) ~0)
1162     snat_vat_api_hookup (vam);
1163
1164   vec_free(name);
1165
1166   return 0;
1167 }