Localize the timeout variable within the W message macro.
[vpp.git] / src / plugins / snat / snat_test.c
1
2 /*
3  * snat.c - skeleton vpp-api-test plug-in 
4  *
5  * Copyright (c) <current-year> <your-organization>
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #include <vat/vat.h>
19 #include <vlibapi/api.h>
20 #include <vlibmemory/api.h>
21 #include <vlibsocket/api.h>
22 #include <vppinfra/error.h>
23 #include <vnet/ip/ip.h>
24
25 #define __plugin_msg_base snat_test_main.msg_id_base
26 #include <vlibapi/vat_helper_macros.h>
27
28 uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
29
30 /* Declare message IDs */
31 #include <snat/snat_msg_enum.h>
32
33 /* define message structures */
34 #define vl_typedefs
35 #include <snat/snat_all_api_h.h> 
36 #undef vl_typedefs
37
38 /* declare message handlers for each api */
39
40 #define vl_endianfun             /* define message structures */
41 #include <snat/snat_all_api_h.h> 
42 #undef vl_endianfun
43
44 /* instantiate all the print functions we know about */
45 #define vl_print(handle, ...)
46 #define vl_printfun
47 #include <snat/snat_all_api_h.h> 
48 #undef vl_printfun
49
50 /* Get the API version number. */
51 #define vl_api_version(n,v) static u32 api_version=(v);
52 #include <snat/snat_all_api_h.h>
53 #undef vl_api_version
54
55 typedef struct {
56     /* API message ID base */
57     u16 msg_id_base;
58     vat_main_t *vat_main;
59 } snat_test_main_t;
60
61 snat_test_main_t snat_test_main;
62
63 #define foreach_standard_reply_retval_handler   \
64 _(snat_add_address_range_reply)                 \
65 _(snat_interface_add_del_feature_reply)         \
66 _(snat_add_static_mapping_reply)                \
67 _(snat_set_workers_reply)                       \
68 _(snat_add_del_interface_addr_reply)            \
69 _(snat_ipfix_enable_disable_reply)
70
71 #define _(n)                                            \
72     static void vl_api_##n##_t_handler                  \
73     (vl_api_##n##_t * mp)                               \
74     {                                                   \
75         vat_main_t * vam = snat_test_main.vat_main;   \
76         i32 retval = ntohl(mp->retval);                 \
77         if (vam->async_mode) {                          \
78             vam->async_errors += (retval < 0);          \
79         } else {                                        \
80             vam->retval = retval;                       \
81             vam->result_ready = 1;                      \
82         }                                               \
83     }
84 foreach_standard_reply_retval_handler;
85 #undef _
86
87 /* 
88  * Table of message reply handlers, must include boilerplate handlers
89  * we just generated
90  */
91 #define foreach_vpe_api_reply_msg                               \
92 _(SNAT_ADD_ADDRESS_RANGE_REPLY, snat_add_address_range_reply)   \
93 _(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY,                         \
94   snat_interface_add_del_feature_reply)                         \
95 _(SNAT_ADD_STATIC_MAPPING_REPLY, snat_add_static_mapping_reply) \
96 _(SNAT_CONTROL_PING_REPLY, snat_control_ping_reply)             \
97 _(SNAT_STATIC_MAPPING_DETAILS, snat_static_mapping_details)     \
98 _(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply)               \
99 _(SNAT_ADDRESS_DETAILS, snat_address_details)                   \
100 _(SNAT_INTERFACE_DETAILS, snat_interface_details)               \
101 _(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply)               \
102 _(SNAT_WORKER_DETAILS, snat_worker_details)                     \
103 _(SNAT_ADD_DEL_INTERFACE_ADDR_REPLY,                            \
104   snat_add_del_interface_addr_reply)                            \
105 _(SNAT_INTERFACE_ADDR_DETAILS, snat_interface_addr_details)     \
106 _(SNAT_IPFIX_ENABLE_DISABLE_REPLY,                              \
107   snat_ipfix_enable_disable_reply)
108
109 static int api_snat_add_address_range (vat_main_t * vam)
110 {
111   unformat_input_t * i = vam->input;
112   ip4_address_t start_addr, end_addr;
113   u32 start_host_order, end_host_order;
114   vl_api_snat_add_address_range_t * mp;
115   u8 is_add = 1;
116   int count;
117
118   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
119     {
120       if (unformat (i, "%U - %U",
121                     unformat_ip4_address, &start_addr,
122                     unformat_ip4_address, &end_addr))
123         ;
124       else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
125         end_addr = start_addr;
126       else if (unformat (i, "del"))
127         is_add = 0;
128       else
129         {
130           clib_warning("unknown input '%U'", format_unformat_error, i);
131           return -99;
132         }
133     }
134
135   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
136   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
137   
138   if (end_host_order < start_host_order)
139     {
140       errmsg ("end address less than start address\n");
141       return -99;
142     }
143
144   count = (end_host_order - start_host_order) + 1;
145
146   if (count > 1024)
147     {
148     errmsg ("%U - %U, %d addresses...\n",
149            format_ip4_address, &start_addr,
150            format_ip4_address, &end_addr,
151            count);
152     }
153   
154   M(SNAT_ADD_ADDRESS_RANGE, mp);
155
156   memcpy (mp->first_ip_address, &start_addr, 4);
157   memcpy (mp->last_ip_address, &end_addr, 4);
158   mp->is_ip4 = 1;
159   mp->is_add = is_add;
160
161   S(mp);
162   W;
163
164   /* NOTREACHED */
165   return 0;
166 }
167
168 static int api_snat_interface_add_del_feature (vat_main_t * vam)
169 {
170   unformat_input_t * i = vam->input;
171   vl_api_snat_interface_add_del_feature_t * mp;
172   u32 sw_if_index;
173   u8 sw_if_index_set = 0;
174   u8 is_inside = 1; 
175   u8 is_add = 1;
176
177   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
178     {
179       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
180         sw_if_index_set = 1;
181       else if (unformat (i, "sw_if_index %d", &sw_if_index))
182         sw_if_index_set = 1;
183       else if (unformat (i, "out"))
184         is_inside = 0;
185       else if (unformat (i, "in"))
186         is_inside = 1;
187       else if (unformat (i, "del"))
188         is_add = 0;
189       else
190         {
191           clib_warning("unknown input '%U'", format_unformat_error, i);
192           return -99;
193         }
194     }
195
196   if (sw_if_index_set == 0)
197     {
198       errmsg ("interface / sw_if_index required\n");
199       return -99;
200     }
201
202   M(SNAT_INTERFACE_ADD_DEL_FEATURE, mp);
203   mp->sw_if_index = ntohl(sw_if_index);
204   mp->is_add = is_add;
205   mp->is_inside = is_inside;
206   
207   S(mp);
208   W;
209   /* NOTREACHED */
210   return 0;
211 }
212
213 static int api_snat_add_static_mapping(vat_main_t * vam)
214 {
215   unformat_input_t * i = vam->input;
216   vl_api_snat_add_static_mapping_t * mp;
217   u8 external_addr_set = 0;
218   u8 local_addr_set;
219   u8 is_add = 1;
220   u8 addr_only = 1;
221   ip4_address_t local_addr, external_addr;
222   u32 local_port = 0, external_port = 0, vrf_id = ~0;
223   u32 sw_if_index = ~0;
224   u8 sw_if_index_set = 0;
225
226   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
227     {
228       if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr))
229         local_addr_set = 1;
230       else if (unformat (i, "external_addr %U", unformat_ip4_address,
231                          &external_addr))
232         external_addr_set = 1;
233       else if (unformat (i, "local_port %u", &local_port))
234         addr_only = 0;
235       else if (unformat (i, "external_port %u", &external_port))
236         addr_only = 0;
237       else if (unformat (i, "external_if %U", unformat_sw_if_index, vam,
238                          &sw_if_index))
239         sw_if_index_set = 1;
240       else if (unformat (i, "external_sw_if_index %d", &sw_if_index))
241         sw_if_index_set = 1;
242        else if (unformat (i, "vrf %u", &vrf_id))
243         ;
244       else if (unformat (i, "del"))
245         is_add = 0;
246       else
247         {
248           clib_warning("unknown input '%U'", format_unformat_error, i);
249           return -99;
250         }
251     }
252
253   if (!local_addr_set)
254     {
255       errmsg ("local addr required\n");
256       return -99;
257     }
258   if (!external_addr_set && !sw_if_index_set)
259     {
260       errmsg ("external addr or interface required\n");
261       return -99;
262     }
263
264   M(SNAT_ADD_STATIC_MAPPING, mp);
265   mp->is_add = is_add;
266   mp->is_ip4 = 1;
267   mp->addr_only = addr_only;
268   mp->local_port = ntohs ((u16) local_port);
269   mp->external_port = ntohs ((u16) external_port);
270   mp->external_sw_if_index = ntohl (sw_if_index);
271   mp->vrf_id = ntohl (vrf_id);
272   memcpy (mp->local_ip_address, &local_addr, 4);
273   memcpy (mp->external_ip_address, &external_addr, 4);
274
275   S(mp);
276   W;
277   /* NOTREACHED */
278   return 0;
279 }
280
281 static void vl_api_snat_control_ping_reply_t_handler
282   (vl_api_snat_control_ping_reply_t * mp)
283 {
284   vat_main_t *vam = &vat_main;
285   i32 retval = ntohl (mp->retval);
286   if (vam->async_mode)
287     {
288       vam->async_errors += (retval < 0);
289     }
290   else
291     {
292       vam->retval = retval;
293       vam->result_ready = 1;
294     }
295 }
296
297 static void vl_api_snat_static_mapping_details_t_handler
298   (vl_api_snat_static_mapping_details_t *mp)
299 {
300   snat_test_main_t * sm = &snat_test_main;
301   vat_main_t *vam = sm->vat_main;
302
303   if (mp->addr_only)
304       fformat (vam->ofp, "%15U%6s%15U%6s%11d\n",
305                format_ip4_address, &mp->local_ip_address, "",
306                format_ip4_address, &mp->external_ip_address, "",
307                ntohl (mp->vrf_id));
308   else
309       fformat (vam->ofp, "%15U%6d%15U%6d%11d\n",
310                format_ip4_address, &mp->local_ip_address,
311                ntohs (mp->local_port),
312                format_ip4_address, &mp->external_ip_address,
313                ntohs (mp->external_port),
314                ntohl (mp->vrf_id));
315
316 }
317
318 static int api_snat_static_mapping_dump(vat_main_t * vam)
319 {
320   vl_api_snat_static_mapping_dump_t * mp;
321
322   if (vam->json_output)
323     {
324       clib_warning ("JSON output not supported for snat_static_mapping_dump");
325       return -99;
326     }
327
328   fformat (vam->ofp, "%21s%21s\n", "local", "external");
329   fformat (vam->ofp, "%15s%6s%15s%6s%11s\n", "address", "port", "address",
330            "port", "vrf");
331
332   M(SNAT_STATIC_MAPPING_DUMP, mp);
333   S(mp);
334   /* Use a control ping for synchronization */
335   {
336     vl_api_snat_control_ping_t *mp;
337     M(SNAT_CONTROL_PING, mp);
338     S(mp);
339   }
340   W;
341   /* NOTREACHED */
342   return 0;
343 }
344
345 static void vl_api_snat_show_config_reply_t_handler
346   (vl_api_snat_show_config_reply_t *mp)
347 {
348   snat_test_main_t * sm = &snat_test_main;
349   vat_main_t *vam = sm->vat_main;
350   i32 retval = ntohl (mp->retval);
351
352   if (retval >= 0)
353     {
354       fformat (vam->ofp, "translation hash buckets %d\n",
355                ntohl (mp->translation_buckets));
356       fformat (vam->ofp, "translation hash memory %d\n",
357                ntohl (mp->translation_memory_size));
358       fformat (vam->ofp, "user hash buckets %d\n", ntohl (mp->user_buckets));
359       fformat (vam->ofp, "user hash memory %d\n", ntohl (mp->user_memory_size));
360       fformat (vam->ofp, "max translations per user %d\n",
361                ntohl (mp->max_translations_per_user));
362       fformat (vam->ofp, "outside VRF id %d\n", ntohl (mp->outside_vrf_id));
363       fformat (vam->ofp, "inside VRF id %d\n", ntohl (mp->inside_vrf_id));
364       if (mp->static_mapping_only)
365         {
366           fformat (vam->ofp, "static mapping only");
367           if (mp->static_mapping_connection_tracking)
368             fformat (vam->ofp, " connection tracking");
369           fformat (vam->ofp, "\n");
370         }
371     }
372   vam->retval = retval;
373   vam->result_ready = 1;
374 }
375
376 static int api_snat_show_config(vat_main_t * vam)
377 {
378   vl_api_snat_show_config_t * mp;
379
380   if (vam->json_output)
381     {
382       clib_warning ("JSON output not supported for snat_show_config");
383       return -99;
384     }
385
386   M(SNAT_SHOW_CONFIG, mp);
387   S(mp);
388   W;
389   /* NOTREACHED */
390   return 0;
391 }
392
393 static void vl_api_snat_address_details_t_handler
394   (vl_api_snat_address_details_t *mp)
395 {
396   snat_test_main_t * sm = &snat_test_main;
397   vat_main_t *vam = sm->vat_main;
398
399   fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address);
400 }
401
402 static int api_snat_address_dump(vat_main_t * vam)
403 {
404   vl_api_snat_address_dump_t * mp;
405
406   if (vam->json_output)
407     {
408       clib_warning ("JSON output not supported for snat_address_dump");
409       return -99;
410     }
411
412   M(SNAT_ADDRESS_DUMP, mp);
413   S(mp);
414   /* Use a control ping for synchronization */
415   {
416     vl_api_snat_control_ping_t *mp;
417     M(SNAT_CONTROL_PING, mp);
418     S(mp);
419   }
420   W;
421   /* NOTREACHED */
422   return 0;
423 }
424
425 static void vl_api_snat_interface_details_t_handler
426   (vl_api_snat_interface_details_t *mp)
427 {
428   snat_test_main_t * sm = &snat_test_main;
429   vat_main_t *vam = sm->vat_main;
430
431   fformat (vam->ofp, "sw_if_index %d %s\n", ntohl (mp->sw_if_index),
432            mp->is_inside ? "in" : "out");
433 }
434
435 static int api_snat_interface_dump(vat_main_t * vam)
436 {
437   vl_api_snat_interface_dump_t * mp;
438
439   if (vam->json_output)
440     {
441       clib_warning ("JSON output not supported for snat_address_dump");
442       return -99;
443     }
444
445   M(SNAT_INTERFACE_DUMP, mp);
446   S(mp);
447   /* Use a control ping for synchronization */
448   {
449     vl_api_snat_control_ping_t *mp;
450     M(SNAT_CONTROL_PING, mp);
451     S(mp);
452   }
453   W;
454   /* NOTREACHED */
455   return 0;
456 }
457
458 static int api_snat_set_workers (vat_main_t * vam)
459 {
460   unformat_input_t * i = vam->input;
461   vl_api_snat_set_workers_t * mp;
462   uword *bitmap;
463
464   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
465     {
466       if (unformat (i, "%U", unformat_bitmap_list, &bitmap))
467         ;
468       else
469         {
470           clib_warning("unknown input '%U'", format_unformat_error, i);
471           return -99;
472         }
473     }
474
475   M(SNAT_SET_WORKERS, mp);
476   mp->worker_mask = clib_host_to_net_u64 (bitmap[0]);
477
478   S(mp);
479   W;
480
481   /* NOTREACHED */
482   return 0;
483 }
484
485 static void vl_api_snat_worker_details_t_handler
486   (vl_api_snat_worker_details_t *mp)
487 {
488   snat_test_main_t * sm = &snat_test_main;
489   vat_main_t *vam = sm->vat_main;
490
491   fformat (vam->ofp, "worker_index %d (%s at lcore %u)\n",
492            ntohl (mp->worker_index), mp->name, ntohl (mp->lcore_id));
493 }
494
495 static int api_snat_worker_dump(vat_main_t * vam)
496 {
497   vl_api_snat_worker_dump_t * mp;
498
499   if (vam->json_output)
500     {
501       clib_warning ("JSON output not supported for snat_address_dump");
502       return -99;
503     }
504
505   M(SNAT_WORKER_DUMP, mp);
506   S(mp);
507   /* Use a control ping for synchronization */
508   {
509     vl_api_snat_control_ping_t *mp;
510     M(SNAT_CONTROL_PING, mp);
511     S(mp);
512   }
513   W;
514   /* NOTREACHED */
515   return 0;
516 }
517
518 static int api_snat_ipfix_enable_disable (vat_main_t * vam)
519 {
520   unformat_input_t * i = vam->input;
521   vl_api_snat_add_del_interface_addr_t * mp;
522   u32 sw_if_index;
523   u8 sw_if_index_set = 0;
524   u8 is_add = 1;
525
526   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
527     {
528       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
529         sw_if_index_set = 1;
530       else if (unformat (i, "sw_if_index %d", &sw_if_index))
531         sw_if_index_set = 1;
532       else if (unformat (i, "del"))
533         is_add = 0;
534       else
535         {
536           clib_warning("unknown input '%U'", format_unformat_error, i);
537           return -99;
538         }
539     }
540
541   if (sw_if_index_set == 0)
542     {
543       errmsg ("interface / sw_if_index required\n");
544       return -99;
545     }
546
547   M(SNAT_ADD_DEL_INTERFACE_ADDR, mp);
548   mp->sw_if_index = ntohl(sw_if_index);
549   mp->is_add = is_add;
550   
551   S(mp);
552   W;
553   /* NOTREACHED */
554   return 0;
555 }
556
557 static void vl_api_snat_interface_addr_details_t_handler
558   (vl_api_snat_interface_addr_details_t *mp)
559 {
560   snat_test_main_t * sm = &snat_test_main;
561   vat_main_t *vam = sm->vat_main;
562
563   fformat (vam->ofp, "sw_if_index %d\n", ntohl (mp->sw_if_index));
564 }
565
566 static int api_snat_interface_addr_dump(vat_main_t * vam)
567 {
568   vl_api_snat_interface_addr_dump_t * mp;
569
570   if (vam->json_output)
571     {
572       clib_warning ("JSON output not supported for snat_address_dump");
573       return -99;
574     }
575
576   M(SNAT_INTERFACE_ADDR_DUMP, mp);
577   S(mp);
578   /* Use a control ping for synchronization */
579   {
580     vl_api_snat_control_ping_t *mp;
581     M(SNAT_CONTROL_PING, mp);
582     S(mp);
583   }
584   W;
585   /* NOTREACHED */
586   return 0;
587 }
588
589 static int api_snat_add_del_interface_addr (vat_main_t * vam)
590 {
591   unformat_input_t * i = vam->input;
592   vl_api_snat_ipfix_enable_disable_t * mp;
593   u32 domain_id = 0;
594   u32 src_port = 0;
595   u8 enable = 1;
596
597   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
598     {
599       if (unformat (i, "domain %d", &domain_id))
600         ;
601       else if (unformat (i, "src_port %d", &src_port))
602         ;
603       else if (unformat (i, "disable"))
604         enable = 0;
605       else
606         {
607           clib_warning("unknown input '%U'", format_unformat_error, i);
608           return -99;
609         }
610     }
611
612   M(SNAT_IPFIX_ENABLE_DISABLE, mp);
613   mp->domain_id = htonl(domain_id);
614   mp->src_port = htons((u16) src_port);
615   mp->enable = enable;
616
617   S(mp);
618   W;
619   /* NOTREACHED */
620   return 0;
621 }
622
623 /* 
624  * List of messages that the api test plugin sends,
625  * and that the data plane plugin processes
626  */
627 #define foreach_vpe_api_msg                                      \
628 _(snat_add_address_range, "<start-addr> [- <end-addr] [del]")    \
629 _(snat_interface_add_del_feature,                                \
630   "<intfc> | sw_if_index <id> [in] [out] [del]")                 \
631 _(snat_add_static_mapping, "local_addr <ip> external_addr <ip> " \
632   "| external_if <intfc> | external_sw_if_ndex <id>) "           \
633   "[local_port <n>] [external_port <n>] [vrf <table-id>] [del]") \
634 _(snat_set_workers, "<wokrers_bitmap>")                          \
635 _(snat_static_mapping_dump, "")                                  \
636 _(snat_show_config, "")                                          \
637 _(snat_address_dump, "")                                         \
638 _(snat_interface_dump, "")                                       \
639 _(snat_worker_dump, "")                                          \
640 _(snat_add_del_interface_addr,                                   \
641   "<intfc> | sw_if_index <id> [del]")                            \
642 _(snat_interface_addr_dump, "")                                  \
643 _(snat_ipfix_enable_disable, "[domain <id>] [src_port <n>] "     \
644   "[disable]")
645
646 static void 
647 snat_vat_api_hookup (vat_main_t *vam)
648 {
649   snat_test_main_t * sm __attribute__((unused)) = &snat_test_main;
650   /* Hook up handlers for replies from the data plane plug-in */
651 #define _(N,n)                                                  \
652   vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),       \
653                           #n,                                   \
654                           vl_api_##n##_t_handler,               \
655                           vl_noop_handler,                      \
656                           vl_api_##n##_t_endian,                \
657                           vl_api_##n##_t_print,                 \
658                           sizeof(vl_api_##n##_t), 1); 
659   foreach_vpe_api_reply_msg;
660 #undef _
661
662   /* API messages we can send */
663 #define _(n,h)                                          \
664   hash_set_mem (vam->function_by_name, #n, api_##n);    \
665   clib_warning ("vam %llx add '%s' handler %llx", vam, #n, api_##n);
666   foreach_vpe_api_msg;
667 #undef _    
668     
669   /* Help strings */
670 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
671   foreach_vpe_api_msg;
672 #undef _
673 }
674
675 clib_error_t * vat_plugin_register (vat_main_t *vam)
676 {
677   snat_test_main_t * sm = &snat_test_main;
678   u8 * name;
679
680   sm->vat_main = vam;
681
682   /* Ask the vpp engine for the first assigned message-id */
683   name = format (0, "snat_%08x%c", api_version, 0);
684   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
685
686   if (sm->msg_id_base != (u16) ~0)
687     snat_vat_api_hookup (vam);
688   
689   vec_free(name);
690   
691   return 0;
692 }