nsim: add packet loss simulation, docs
[vpp.git] / src / plugins / nsim / nsim_test.c
1 /*
2  * nsim.c - skeleton vpp-api-test plug-in
3  *
4  * Copyright (c) <current-year> <your-organization>
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <vat/vat.h>
18 #include <vlibapi/api.h>
19 #include <vlibmemory/api.h>
20 #include <vppinfra/error.h>
21
22 uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
23
24 /* Declare message IDs */
25 #include <nsim/nsim_msg_enum.h>
26
27 /* define message structures */
28 #define vl_typedefs
29 #include <nsim/nsim_all_api_h.h>
30 #undef vl_typedefs
31
32 /* declare message handlers for each api */
33
34 #define vl_endianfun            /* define message structures */
35 #include <nsim/nsim_all_api_h.h>
36 #undef vl_endianfun
37
38 /* instantiate all the print functions we know about */
39 #define vl_print(handle, ...)
40 #define vl_printfun
41 #include <nsim/nsim_all_api_h.h>
42 #undef vl_printfun
43
44 /* Get the API version number. */
45 #define vl_api_version(n,v) static u32 api_version=(v);
46 #include <nsim/nsim_all_api_h.h>
47 #undef vl_api_version
48
49
50 typedef struct
51 {
52   /* API message ID base */
53   u16 msg_id_base;
54   vat_main_t *vat_main;
55 } nsim_test_main_t;
56
57 nsim_test_main_t nsim_test_main;
58
59 #define __plugin_msg_base nsim_test_main.msg_id_base
60 #include <vlibapi/vat_helper_macros.h>
61
62 #define foreach_standard_reply_retval_handler   \
63 _(nsim_enable_disable_reply)                    \
64 _(nsim_configure_reply)
65
66 #define _(n)                                            \
67     static void vl_api_##n##_t_handler                  \
68     (vl_api_##n##_t * mp)                               \
69     {                                                   \
70         vat_main_t * vam = nsim_test_main.vat_main;   \
71         i32 retval = ntohl(mp->retval);                 \
72         if (vam->async_mode) {                          \
73             vam->async_errors += (retval < 0);          \
74         } else {                                        \
75             vam->retval = retval;                       \
76             vam->result_ready = 1;                      \
77         }                                               \
78     }
79 foreach_standard_reply_retval_handler;
80 #undef _
81
82 /*
83  * Table of message reply handlers, must include boilerplate handlers
84  * we just generated
85  */
86 #define foreach_vpe_api_reply_msg                       \
87 _(NSIM_ENABLE_DISABLE_REPLY, nsim_enable_disable_reply) \
88 _(NSIM_CONFIGURE_REPLY, nsim_configure_reply)
89
90 static int
91 api_nsim_enable_disable (vat_main_t * vam)
92 {
93   unformat_input_t *i = vam->input;
94   int enable_disable = 1;
95   u32 sw_if_index0 = ~0;
96   u32 sw_if_index1 = ~0;
97   u32 tmp;
98   vl_api_nsim_enable_disable_t *mp;
99   int ret;
100
101   /* Parse args required to build the message */
102   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
103     {
104       if (unformat (i, "%U", unformat_sw_if_index, vam, &tmp))
105         {
106           if (sw_if_index0 == ~0)
107             sw_if_index0 = tmp;
108           else
109             sw_if_index1 = tmp;
110         }
111       else if (unformat (i, "sw_if_index %d", &tmp))
112         {
113           if (sw_if_index0 == ~0)
114             sw_if_index0 = tmp;
115           else
116             sw_if_index1 = tmp;
117         }
118       else if (unformat (i, "disable"))
119         enable_disable = 0;
120       else
121         break;
122     }
123
124   if (sw_if_index0 == ~0 || sw_if_index1 == ~0)
125     {
126       errmsg ("missing interface name / explicit sw_if_index number \n");
127       return -99;
128     }
129
130   /* Construct the API message */
131   M (NSIM_ENABLE_DISABLE, mp);
132   mp->sw_if_index0 = ntohl (sw_if_index0);
133   mp->sw_if_index1 = ntohl (sw_if_index1);
134   mp->enable_disable = enable_disable;
135
136   /* send it... */
137   S (mp);
138
139   /* Wait for a reply... */
140   W (ret);
141   return ret;
142 }
143
144 static uword
145 unformat_delay (unformat_input_t * input, va_list * args)
146 {
147   f64 *result = va_arg (*args, f64 *);
148   f64 tmp;
149
150   if (unformat (input, "%f us", &tmp))
151     *result = tmp * 1e-6;
152   else if (unformat (input, "%f ms", &tmp))
153     *result = tmp * 1e-3;
154   else if (unformat (input, "%f sec", &tmp))
155     *result = tmp;
156   else
157     return 0;
158
159   return 1;
160 }
161
162 static uword
163 unformat_bandwidth (unformat_input_t * input, va_list * args)
164 {
165   f64 *result = va_arg (*args, f64 *);
166   f64 tmp;
167
168   if (unformat (input, "%f gbit", &tmp))
169     *result = tmp * 1e9;
170   else if (unformat (input, "%f gbyte", &tmp))
171     *result = tmp * 8e9;
172   else
173     return 0;
174   return 1;
175 }
176
177 static int
178 api_nsim_configure (vat_main_t * vam)
179 {
180   vl_api_nsim_configure_t *mp;
181   unformat_input_t *i = vam->input;
182   f64 delay = 0.0, bandwidth = 0.0;
183   f64 packet_size = 1500.0;
184   u32 num_workers = vlib_num_workers ();
185   u32 packets_per_drop = 0;
186   int ret;
187
188   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
189     {
190       if (unformat (i, "delay %U", unformat_delay, &delay))
191         ;
192       else if (unformat (i, "bandwidth %U", unformat_bandwidth, &bandwidth))
193         ;
194       else if (unformat (i, "packet-size %f", &packet_size))
195         ;
196       else if (unformat (i, "packets-per-drop %u", &packets_per_drop))
197         ;
198       else
199         break;
200     }
201
202   if (delay == 0.0 || bandwidth == 0.0)
203     {
204       errmsg ("must specify delay and bandwidth");
205       return -99;
206     }
207
208   /* Construct the API message */
209   M (NSIM_CONFIGURE, mp);
210   mp->delay_in_usec = (u32) (delay * 1e6);
211   mp->delay_in_usec = ntohl (mp->delay_in_usec);
212   mp->average_packet_size = (u32) (packet_size);
213   mp->average_packet_size = ntohl (mp->average_packet_size);
214   mp->bandwidth_in_bits_per_second = (u64) (bandwidth);
215   mp->bandwidth_in_bits_per_second =
216     clib_host_to_net_u64 (mp->bandwidth_in_bits_per_second);
217   mp->packets_per_drop = ntohl (packets_per_drop);
218
219   /* send it... */
220   S (mp);
221
222   /* Wait for a reply... */
223   W (ret);
224   return ret;
225 }
226
227 /*
228  * List of messages that the api test plugin sends,
229  * and that the data plane plugin processes
230  */
231 #define foreach_vpe_api_msg                                             \
232 _(nsim_enable_disable,                                                  \
233 "[<intfc0> | sw_if_index <swif0>] [<intfc1> | sw_if_index <swif1>] [disable]") \
234 _(nsim_configure, "delay <time> bandwidth <bw> [packet-size <nn>]" \
235 "[packets-per-drop <nnnn>]")
236
237 static void
238 nsim_api_hookup (vat_main_t * vam)
239 {
240   nsim_test_main_t *sm = &nsim_test_main;
241   /* Hook up handlers for replies from the data plane plug-in */
242 #define _(N,n)                                                  \
243     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
244                            #n,                                  \
245                            vl_api_##n##_t_handler,              \
246                            vl_noop_handler,                     \
247                            vl_api_##n##_t_endian,               \
248                            vl_api_##n##_t_print,                \
249                            sizeof(vl_api_##n##_t), 1);
250   foreach_vpe_api_reply_msg;
251 #undef _
252
253   /* API messages we can send */
254 #define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
255   foreach_vpe_api_msg;
256 #undef _
257
258   /* Help strings */
259 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
260   foreach_vpe_api_msg;
261 #undef _
262 }
263
264 clib_error_t *
265 vat_plugin_register (vat_main_t * vam)
266 {
267   nsim_test_main_t *sm = &nsim_test_main;
268   u8 *name;
269
270   sm->vat_main = vam;
271
272   /* Ask the vpp engine for the first assigned message-id */
273   name = format (0, "nsim_%08x%c", api_version, 0);
274   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
275
276   if (sm->msg_id_base != (u16) ~ 0)
277     nsim_api_hookup (vam);
278
279   vec_free (name);
280
281   return 0;
282 }
283
284 /*
285  * fd.io coding-style-patch-verification: ON
286  *
287  * Local Variables:
288  * eval: (c-set-style "gnu")
289  * End:
290  */