Make the loss / delay sim available as an output feature
[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_cross_connect_enable_disable_reply)      \
64 _(nsim_output_feature_enable_disable_reply)     \
65 _(nsim_configure_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 = nsim_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 _(NSIM_CROSS_CONNECT_ENABLE_DISABLE_REPLY,      \
89 nsim_cross_connect_enable_disable_reply)        \
90 _(NSIM_OUTPUT_FEATURE_ENABLE_DISABLE_REPLY,     \
91 nsim_output_feature_enable_disable_reply)       \
92 _(NSIM_CONFIGURE_REPLY, nsim_configure_reply)
93
94 static int
95 api_nsim_cross_connect_enable_disable (vat_main_t * vam)
96 {
97   unformat_input_t *i = vam->input;
98   int enable_disable = 1;
99   u32 sw_if_index0 = ~0;
100   u32 sw_if_index1 = ~0;
101   u32 tmp;
102   vl_api_nsim_cross_connect_enable_disable_t *mp;
103   int ret;
104
105   /* Parse args required to build the message */
106   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
107     {
108       if (unformat (i, "%U", unformat_sw_if_index, vam, &tmp))
109         {
110           if (sw_if_index0 == ~0)
111             sw_if_index0 = tmp;
112           else
113             sw_if_index1 = tmp;
114         }
115       else if (unformat (i, "sw_if_index %d", &tmp))
116         {
117           if (sw_if_index0 == ~0)
118             sw_if_index0 = tmp;
119           else
120             sw_if_index1 = tmp;
121         }
122       else if (unformat (i, "disable"))
123         enable_disable = 0;
124       else
125         break;
126     }
127
128   if (sw_if_index0 == ~0 || sw_if_index1 == ~0)
129     {
130       errmsg ("missing interface name / explicit sw_if_index number \n");
131       return -99;
132     }
133
134   /* Construct the API message */
135   M (NSIM_CROSS_CONNECT_ENABLE_DISABLE, mp);
136   mp->sw_if_index0 = ntohl (sw_if_index0);
137   mp->sw_if_index1 = ntohl (sw_if_index1);
138   mp->enable_disable = enable_disable;
139
140   /* send it... */
141   S (mp);
142
143   /* Wait for a reply... */
144   W (ret);
145   return ret;
146 }
147
148 static int
149 api_nsim_output_feature_enable_disable (vat_main_t * vam)
150 {
151   unformat_input_t *i = vam->input;
152   int enable_disable = 1;
153   u32 sw_if_index = ~0;
154   vl_api_nsim_output_feature_enable_disable_t *mp;
155   int ret;
156
157   /* Parse args required to build the message */
158   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
159     {
160       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
161         ;
162       else if (unformat (i, "sw_if_index %d", &sw_if_index))
163         ;
164       else if (unformat (i, "disable"))
165         enable_disable = 0;
166       else
167         break;
168     }
169
170   if (sw_if_index == ~0)
171     {
172       errmsg ("missing interface name / explicit sw_if_index number \n");
173       return -99;
174     }
175
176   /* Construct the API message */
177   M (NSIM_OUTPUT_FEATURE_ENABLE_DISABLE, mp);
178   mp->sw_if_index = ntohl (sw_if_index);
179   mp->enable_disable = enable_disable;
180
181   /* send it... */
182   S (mp);
183
184   /* Wait for a reply... */
185   W (ret);
186   return ret;
187 }
188
189 static uword
190 unformat_delay (unformat_input_t * input, va_list * args)
191 {
192   f64 *result = va_arg (*args, f64 *);
193   f64 tmp;
194
195   if (unformat (input, "%f us", &tmp))
196     *result = tmp * 1e-6;
197   else if (unformat (input, "%f ms", &tmp))
198     *result = tmp * 1e-3;
199   else if (unformat (input, "%f sec", &tmp))
200     *result = tmp;
201   else
202     return 0;
203
204   return 1;
205 }
206
207 static uword
208 unformat_bandwidth (unformat_input_t * input, va_list * args)
209 {
210   f64 *result = va_arg (*args, f64 *);
211   f64 tmp;
212
213   if (unformat (input, "%f gbit", &tmp))
214     *result = tmp * 1e9;
215   else if (unformat (input, "%f gbyte", &tmp))
216     *result = tmp * 8e9;
217   else
218     return 0;
219   return 1;
220 }
221
222 static int
223 api_nsim_configure (vat_main_t * vam)
224 {
225   vl_api_nsim_configure_t *mp;
226   unformat_input_t *i = vam->input;
227   f64 delay = 0.0, bandwidth = 0.0;
228   f64 packet_size = 1500.0;
229   u32 num_workers = vlib_num_workers ();
230   u32 packets_per_drop = 0;
231   int ret;
232
233   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
234     {
235       if (unformat (i, "delay %U", unformat_delay, &delay))
236         ;
237       else if (unformat (i, "bandwidth %U", unformat_bandwidth, &bandwidth))
238         ;
239       else if (unformat (i, "packet-size %f", &packet_size))
240         ;
241       else if (unformat (i, "packets-per-drop %u", &packets_per_drop))
242         ;
243       else
244         break;
245     }
246
247   if (delay == 0.0 || bandwidth == 0.0)
248     {
249       errmsg ("must specify delay and bandwidth");
250       return -99;
251     }
252
253   /* Construct the API message */
254   M (NSIM_CONFIGURE, mp);
255   mp->delay_in_usec = (u32) (delay * 1e6);
256   mp->delay_in_usec = ntohl (mp->delay_in_usec);
257   mp->average_packet_size = (u32) (packet_size);
258   mp->average_packet_size = ntohl (mp->average_packet_size);
259   mp->bandwidth_in_bits_per_second = (u64) (bandwidth);
260   mp->bandwidth_in_bits_per_second =
261     clib_host_to_net_u64 (mp->bandwidth_in_bits_per_second);
262   mp->packets_per_drop = ntohl (packets_per_drop);
263
264   /* send it... */
265   S (mp);
266
267   /* Wait for a reply... */
268   W (ret);
269   return ret;
270 }
271
272 /*
273  * List of messages that the api test plugin sends,
274  * and that the data plane plugin processes
275  */
276 #define foreach_vpe_api_msg                                             \
277 _(nsim_cross_connect_enable_disable,                                    \
278 "[<intfc0> | sw_if_index <swif0>] [<intfc1> | sw_if_index <swif1>] [disable]") \
279 _(nsim_output_feature_enable_disable,"[<intfc> | sw_if_index <nnn> [disable]") \
280 _(nsim_configure, "delay <time> bandwidth <bw> [packet-size <nn>]"      \
281 "[packets-per-drop <nnnn>]")
282
283 static void
284 nsim_api_hookup (vat_main_t * vam)
285 {
286   nsim_test_main_t *sm = &nsim_test_main;
287   /* Hook up handlers for replies from the data plane plug-in */
288 #define _(N,n)                                                  \
289     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
290                            #n,                                  \
291                            vl_api_##n##_t_handler,              \
292                            vl_noop_handler,                     \
293                            vl_api_##n##_t_endian,               \
294                            vl_api_##n##_t_print,                \
295                            sizeof(vl_api_##n##_t), 1);
296   foreach_vpe_api_reply_msg;
297 #undef _
298
299   /* API messages we can send */
300 #define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
301   foreach_vpe_api_msg;
302 #undef _
303
304   /* Help strings */
305 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
306   foreach_vpe_api_msg;
307 #undef _
308 }
309
310 clib_error_t *
311 vat_plugin_register (vat_main_t * vam)
312 {
313   nsim_test_main_t *sm = &nsim_test_main;
314   u8 *name;
315
316   sm->vat_main = vam;
317
318   /* Ask the vpp engine for the first assigned message-id */
319   name = format (0, "nsim_%08x%c", api_version, 0);
320   sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
321
322   if (sm->msg_id_base != (u16) ~ 0)
323     nsim_api_hookup (vam);
324
325   vec_free (name);
326
327   return 0;
328 }
329
330 /*
331  * fd.io coding-style-patch-verification: ON
332  *
333  * Local Variables:
334  * eval: (c-set-style "gnu")
335  * End:
336  */