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