nsim: remove buffer u32 upper bound
[vpp.git] / src / plugins / nsim / nsim.c
1 /*
2  * nsim.c - skeleton vpp engine 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
18 /**
19  * @file
20  * @brief Network Delay Simulator
21  */
22 /*? %%clicmd:group_label Network Delay Simulator %% ?*/
23
24 #include <vnet/vnet.h>
25 #include <vnet/plugin/plugin.h>
26 #include <nsim/nsim.h>
27
28 #include <vlibapi/api.h>
29 #include <vlibmemory/api.h>
30 #include <vpp/app/version.h>
31
32 /* define message IDs */
33 #include <nsim/nsim_msg_enum.h>
34
35 /* define message structures */
36 #define vl_typedefs
37 #include <nsim/nsim_all_api_h.h>
38 #undef vl_typedefs
39
40 /* define generated endian-swappers */
41 #define vl_endianfun
42 #include <nsim/nsim_all_api_h.h>
43 #undef vl_endianfun
44
45 /* instantiate all the print functions we know about */
46 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
47 #define vl_printfun
48 #include <nsim/nsim_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 <nsim/nsim_all_api_h.h>
54 #undef vl_api_version
55
56 #define REPLY_MSG_ID_BASE nsm->msg_id_base
57 #include <vlibapi/api_helper_macros.h>
58
59 nsim_main_t nsim_main;
60
61 /* List of message types that this plugin understands */
62
63 #define foreach_nsim_plugin_api_msg                                     \
64 _(NSIM_CROSS_CONNECT_ENABLE_DISABLE, nsim_cross_connect_enable_disable) \
65 _(NSIM_OUTPUT_FEATURE_ENABLE_DISABLE, nsim_output_feature_enable_disable) \
66 _(NSIM_CONFIGURE, nsim_configure)
67
68 /* Action functions shared between message handlers and debug CLI */
69
70 int
71 nsim_cross_connect_enable_disable (nsim_main_t * nsm, u32 sw_if_index0,
72                                    u32 sw_if_index1, int enable_disable)
73 {
74   vnet_sw_interface_t *sw;
75   vnet_hw_interface_t *hw;
76   int rv = 0;
77
78   if (nsm->is_configured == 0)
79     return VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
80
81   /* Utterly wrong? */
82   if (pool_is_free_index (nsm->vnet_main->interface_main.sw_interfaces,
83                           sw_if_index0))
84     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
85
86   if (pool_is_free_index (nsm->vnet_main->interface_main.sw_interfaces,
87                           sw_if_index1))
88     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
89
90   /* Not a physical port? */
91   sw = vnet_get_sw_interface (nsm->vnet_main, sw_if_index0);
92   if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
93     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
94
95   sw = vnet_get_sw_interface (nsm->vnet_main, sw_if_index1);
96   if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
97     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
98
99   /* Add graph arcs for the input / wheel scraper node */
100   hw = vnet_get_hw_interface (nsm->vnet_main, sw_if_index0);
101   nsm->output_next_index0 =
102     vlib_node_add_next (nsm->vlib_main,
103                         nsim_input_node.index, hw->output_node_index);
104
105   hw = vnet_get_hw_interface (nsm->vnet_main, sw_if_index1);
106   nsm->output_next_index1 =
107     vlib_node_add_next (nsm->vlib_main,
108                         nsim_input_node.index, hw->output_node_index);
109
110   nsm->sw_if_index0 = sw_if_index0;
111   nsm->sw_if_index1 = sw_if_index1;
112
113   vnet_feature_enable_disable ("device-input", "nsim",
114                                sw_if_index0, enable_disable, 0, 0);
115   vnet_feature_enable_disable ("device-input", "nsim",
116                                sw_if_index1, enable_disable, 0, 0);
117
118   return rv;
119 }
120
121 int
122 nsim_output_feature_enable_disable (nsim_main_t * nsm, u32 sw_if_index,
123                                     int enable_disable)
124 {
125   vnet_sw_interface_t *sw;
126   vnet_hw_interface_t *hw;
127   int rv = 0;
128
129   if (nsm->is_configured == 0)
130     return VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
131
132   /* Utterly wrong? */
133   if (pool_is_free_index (nsm->vnet_main->interface_main.sw_interfaces,
134                           sw_if_index))
135     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
136
137   /* Not a physical port? */
138   sw = vnet_get_sw_interface (nsm->vnet_main, sw_if_index);
139   if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
140     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
141
142   /* Add a graph arc for the input / wheel scraper node */
143   hw = vnet_get_hw_interface (nsm->vnet_main, sw_if_index);
144   vec_validate_init_empty (nsm->output_next_index_by_sw_if_index, sw_if_index,
145                            ~0);
146   /* Note: use the tx node, this pkt has already visited the output node... */
147   nsm->output_next_index_by_sw_if_index[sw_if_index] =
148     vlib_node_add_next (nsm->vlib_main, nsim_input_node.index,
149                         hw->tx_node_index);
150
151   vnet_feature_enable_disable ("interface-output", "nsim-output-feature",
152                                sw_if_index, enable_disable, 0, 0);
153   return rv;
154 }
155
156 static int
157 nsim_configure (nsim_main_t * nsm, f64 bandwidth, f64 delay, f64 packet_size,
158                 f64 drop_fraction)
159 {
160   u64 total_buffer_size_in_bytes, per_worker_buffer_size;
161   u64 wheel_slots_per_worker;
162   int i;
163   int num_workers = vlib_num_workers ();
164   u32 pagesize = getpagesize ();
165   vlib_main_t *vm = nsm->vlib_main;
166
167   if (bandwidth == 0.0)
168     return VNET_API_ERROR_INVALID_VALUE;
169
170   if (delay == 0.0)
171     return VNET_API_ERROR_INVALID_VALUE_2;
172
173   if (packet_size < 64.0 || packet_size > 9000.0)
174     return VNET_API_ERROR_INVALID_VALUE_3;
175
176   /* Toss the old wheel(s)... */
177   if (nsm->is_configured)
178     {
179       for (i = 0; i < vec_len (nsm->wheel_by_thread); i++)
180         {
181           nsim_wheel_t *wp = nsm->wheel_by_thread[i];
182           munmap (wp, nsm->mmap_size);
183           nsm->wheel_by_thread[i] = 0;
184         }
185     }
186
187   nsm->delay = delay;
188   nsm->drop_fraction = drop_fraction;
189
190   /* delay in seconds, bandwidth in bits/sec */
191   total_buffer_size_in_bytes = ((delay * bandwidth) / 8.0) + 0.5;
192
193   /*
194    * Work out how much buffering each worker needs, assuming decent
195    * RSS behavior.
196    */
197   if (num_workers)
198     per_worker_buffer_size = total_buffer_size_in_bytes / num_workers;
199   else
200     per_worker_buffer_size = total_buffer_size_in_bytes;
201
202   wheel_slots_per_worker = per_worker_buffer_size / packet_size;
203   wheel_slots_per_worker++;
204
205   /* Save these for the show command */
206   nsm->bandwidth = bandwidth;
207   nsm->packet_size = packet_size;
208
209   vec_validate (nsm->wheel_by_thread, num_workers);
210
211   /* Initialize the output scheduler wheels */
212   for (i = num_workers ? 1 : 0; i < num_workers + 1; i++)
213     {
214       nsim_wheel_t *wp;
215
216       nsm->mmap_size = sizeof (nsim_wheel_t)
217         + wheel_slots_per_worker * sizeof (nsim_wheel_entry_t);
218
219       nsm->mmap_size += pagesize - 1;
220       nsm->mmap_size &= ~(pagesize - 1);
221
222       wp = clib_mem_vm_alloc (nsm->mmap_size);
223       ASSERT (wp != 0);
224       wp->wheel_size = wheel_slots_per_worker;
225       wp->cursize = 0;
226       wp->head = 0;
227       wp->tail = 0;
228       wp->entries = (void *) (wp + 1);
229       nsm->wheel_by_thread[i] = wp;
230     }
231
232   vlib_worker_thread_barrier_sync (vm);
233
234   /* turn on the ring scrapers */
235   for (i = num_workers ? 1 : 0; i < num_workers + 1; i++)
236     {
237       vlib_main_t *this_vm = vlib_mains[i];
238
239       vlib_node_set_state (this_vm, nsim_input_node.index,
240                            VLIB_NODE_STATE_POLLING);
241     }
242
243   vlib_worker_thread_barrier_release (vm);
244
245   nsm->is_configured = 1;
246   return 0;
247 }
248
249 /*
250  * enable or disable the cross-connect
251  */
252 static clib_error_t *
253 nsim_cross_connect_enable_disable_command_fn (vlib_main_t * vm,
254                                               unformat_input_t * input,
255                                               vlib_cli_command_t * cmd)
256 {
257   nsim_main_t *nsm = &nsim_main;
258   unformat_input_t _line_input, *line_input = &_line_input;
259   u32 sw_if_index0 = ~0;
260   u32 sw_if_index1 = ~0;
261   int enable_disable = 1;
262   u32 tmp;
263   int rv;
264
265   /* Get a line of input. */
266   if (!unformat_user (input, unformat_line_input, line_input))
267     return 0;
268
269   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
270     {
271       if (unformat (line_input, "disable"))
272         enable_disable = 0;
273       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
274                          nsm->vnet_main, &tmp))
275         {
276           if (sw_if_index0 == ~0)
277             sw_if_index0 = tmp;
278           else
279             sw_if_index1 = tmp;
280         }
281       else
282         break;
283     }
284
285   unformat_free (line_input);
286
287   if (sw_if_index0 == ~0 || sw_if_index1 == ~0)
288     return clib_error_return (0, "Please specify two interfaces...");
289
290   rv = nsim_cross_connect_enable_disable (nsm, sw_if_index0,
291                                           sw_if_index1, enable_disable);
292
293   switch (rv)
294     {
295     case 0:
296       break;
297
298     case VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE:
299       return clib_error_return (0, "Not configured, please 'set nsim' first");
300
301     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
302       return clib_error_return
303         (0, "Invalid interface, only works on physical ports");
304       break;
305
306     case VNET_API_ERROR_UNIMPLEMENTED:
307       return clib_error_return (0,
308                                 "Device driver doesn't support redirection");
309       break;
310
311     default:
312       return clib_error_return (0, "nsim_enable_disable returned %d", rv);
313     }
314   return 0;
315 }
316
317 /*?
318  * Enable or disable network simulation cross-connect on two interfaces
319  * The network simulator must have already been configured, see
320  * the "nsim_configure" command.
321  *
322  * Place the interfaces into a bridge group, to ensure that
323  * interfaces are in promiscuous mode.
324  *
325  * @cliexpar
326  * To enable or disable network simulation cross-connect
327  * @clistart
328  * nsim cross-connect enable-disable TenGigabitEthernet2/0/0 TenGigabitEthernet2/0
329  * nsim cross-connect enable-disable TenGigabitEthernet2/0/0 TenGigabitEthernet2/0 disable
330  * @cliend
331  * @cliexcmd{nsim enable-disable <intfc> <intfc> [disable]}
332 ?*/
333 /* *INDENT-OFF* */
334 VLIB_CLI_COMMAND (nsim_enable_disable_command, static) =
335 {
336   .path = "nsim cross-connect enable-disable",
337   .short_help =
338   "nsim cross-connect enable-disable <interface-name-1> "
339   "<interface-name-2> [disable]",
340   .function = nsim_cross_connect_enable_disable_command_fn,
341 };
342 /* *INDENT-ON* */
343
344 /* API message handler */
345 static void vl_api_nsim_cross_connect_enable_disable_t_handler
346   (vl_api_nsim_cross_connect_enable_disable_t * mp)
347 {
348   vl_api_nsim_cross_connect_enable_disable_reply_t *rmp;
349   nsim_main_t *nsm = &nsim_main;
350   int rv;
351   u32 sw_if_index0, sw_if_index1;
352
353   sw_if_index0 = clib_net_to_host_u32 (mp->sw_if_index0);
354   sw_if_index1 = clib_net_to_host_u32 (mp->sw_if_index1);
355
356   if (!vnet_sw_if_index_is_api_valid (sw_if_index0))
357     {
358       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
359       goto bad_sw_if_index;
360     }
361   if (!vnet_sw_if_index_is_api_valid (sw_if_index1))
362     {
363       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
364       goto bad_sw_if_index;
365     }
366
367   rv = nsim_cross_connect_enable_disable (nsm, sw_if_index0, sw_if_index1,
368                                           (int) (mp->enable_disable));
369
370   BAD_SW_IF_INDEX_LABEL;
371   REPLY_MACRO (VL_API_NSIM_CROSS_CONNECT_ENABLE_DISABLE_REPLY);
372 }
373
374 /* API message handler */
375 static void vl_api_nsim_output_feature_enable_disable_t_handler
376   (vl_api_nsim_output_feature_enable_disable_t * mp)
377 {
378   vl_api_nsim_output_feature_enable_disable_reply_t *rmp;
379   nsim_main_t *nsm = &nsim_main;
380   int rv;
381   VALIDATE_SW_IF_INDEX (mp);
382
383   rv = nsim_output_feature_enable_disable (nsm, ntohl (mp->sw_if_index),
384                                            (int) (mp->enable_disable));
385
386   BAD_SW_IF_INDEX_LABEL;
387   REPLY_MACRO (VL_API_NSIM_OUTPUT_FEATURE_ENABLE_DISABLE_REPLY);
388 }
389
390 /* API message handler */
391 static void
392 vl_api_nsim_configure_t_handler (vl_api_nsim_configure_t * mp)
393 {
394   vl_api_nsim_configure_reply_t *rmp;
395   nsim_main_t *nsm = &nsim_main;
396   f64 delay, bandwidth, packet_size, drop_fraction;
397   u32 packets_per_drop;
398   int rv;
399
400   delay = ((f64) (ntohl (mp->delay_in_usec))) * 1e-6;
401   bandwidth = (f64) (clib_net_to_host_u64 (mp->bandwidth_in_bits_per_second));
402   packet_size = (f64) (ntohl (mp->average_packet_size));
403
404   packets_per_drop = ntohl (mp->packets_per_drop);
405   if (packets_per_drop > 0)
406     drop_fraction = 1.0 / (f64) (packets_per_drop);
407   else
408     drop_fraction = 0.0;
409
410   rv = nsim_configure (nsm, bandwidth, delay, packet_size, drop_fraction);
411
412   REPLY_MACRO (VL_API_NSIM_CONFIGURE_REPLY);
413 }
414
415
416 /*
417  * enable or disable the output_feature
418  */
419 static clib_error_t *
420 nsim_output_feature_enable_disable_command_fn (vlib_main_t * vm,
421                                                unformat_input_t * input,
422                                                vlib_cli_command_t * cmd)
423 {
424   nsim_main_t *nsm = &nsim_main;
425   unformat_input_t _line_input, *line_input = &_line_input;
426   u32 sw_if_index = ~0;
427   int enable_disable = 1;
428   int rv;
429
430   /* Get a line of input. */
431   if (!unformat_user (input, unformat_line_input, line_input))
432     return 0;
433
434   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
435     {
436       if (unformat (line_input, "disable"))
437         enable_disable = 0;
438       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
439                          nsm->vnet_main, &sw_if_index))
440         ;
441       else
442         {
443           clib_error_t *error = clib_error_return (0, "unknown input `%U'",
444                                                    format_unformat_error,
445                                                    line_input);
446           unformat_free (line_input);
447           return error;
448         }
449     }
450
451   unformat_free (line_input);
452
453   if (sw_if_index == ~0)
454     return clib_error_return (0, "Please specify one interface...");
455
456   rv = nsim_output_feature_enable_disable (nsm, sw_if_index, enable_disable);
457
458   switch (rv)
459     {
460     case 0:
461       break;
462
463     case VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE:
464       return clib_error_return (0, "Not configured, please 'set nsim' first");
465
466     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
467       return clib_error_return
468         (0, "Invalid interface, only works on physical ports");
469       break;
470
471     case VNET_API_ERROR_UNIMPLEMENTED:
472       return clib_error_return (0,
473                                 "Device driver doesn't support redirection");
474       break;
475
476     default:
477       return clib_error_return
478         (0, "nsim_output_feature_enable_disable returned %d", rv);
479     }
480   return 0;
481 }
482
483 /*?
484  * Enable or disable network simulation output feature on an interface
485  * The network simulator must have already been configured, see
486  * the "nsim_configure" command.
487  *
488  * @cliexpar
489  * To enable or disable network simulation output feature
490  * @clistart
491  * nsim output-feature enable-disable TenGigabitEthernet2/0/0
492  * nsim output-feature enable-disable TenGigabitEthernet2/0/0 disable
493  * @cliend
494  * @cliexcmd{nsim output-feature enable-disable <intfc> [disable]}
495 ?*/
496 /* *INDENT-OFF* */
497 VLIB_CLI_COMMAND (nsim_output_feature_enable_disable_command, static) =
498 {
499   .path = "nsim output-feature enable-disable",
500   .short_help =
501   "nsim output-feature enable-disable <interface-name> [disable]",
502   .function = nsim_output_feature_enable_disable_command_fn,
503 };
504 /* *INDENT-ON* */
505
506 /* Set up the API message handling tables */
507 static clib_error_t *
508 nsim_plugin_api_hookup (vlib_main_t * vm)
509 {
510   nsim_main_t *nsm = &nsim_main;
511 #define _(N,n)                                                  \
512     vl_msg_api_set_handlers((VL_API_##N + nsm->msg_id_base),     \
513                            #n,                                  \
514                            vl_api_##n##_t_handler,              \
515                            vl_noop_handler,                     \
516                            vl_api_##n##_t_endian,               \
517                            vl_api_##n##_t_print,                \
518                            sizeof(vl_api_##n##_t), 1);
519   foreach_nsim_plugin_api_msg;
520 #undef _
521
522   return 0;
523 }
524
525 #define vl_msg_name_crc_list
526 #include <nsim/nsim_all_api_h.h>
527 #undef vl_msg_name_crc_list
528
529 static void
530 setup_message_id_table (nsim_main_t * nsm, api_main_t * am)
531 {
532 #define _(id,n,crc)   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nsm->msg_id_base);
533   foreach_vl_msg_name_crc_nsim;
534 #undef _
535 }
536
537 static clib_error_t *
538 nsim_init (vlib_main_t * vm)
539 {
540   nsim_main_t *nsm = &nsim_main;
541   clib_error_t *error = 0;
542   u8 *name;
543
544   nsm->vlib_main = vm;
545   nsm->vnet_main = vnet_get_main ();
546
547   name = format (0, "nsim_%08x%c", api_version, 0);
548
549   /* Ask for a correctly-sized block of API message decode slots */
550   nsm->msg_id_base = vl_msg_api_get_msg_ids
551     ((char *) name, VL_MSG_FIRST_AVAILABLE);
552
553   error = nsim_plugin_api_hookup (vm);
554
555   /* Add our API messages to the global name_crc hash table */
556   setup_message_id_table (nsm, &api_main);
557
558   vec_free (name);
559
560   return error;
561 }
562
563 VLIB_INIT_FUNCTION (nsim_init);
564
565 /* *INDENT-OFF* */
566 VNET_FEATURE_INIT (nsim, static) =
567 {
568   .arc_name = "device-input",
569   .node_name = "nsim",
570   .runs_before = VNET_FEATURES ("ethernet-input"),
571 };
572 /* *INDENT-ON */
573
574 /* *INDENT-OFF* */
575 VNET_FEATURE_INIT (nsim_feature, static) =
576 {
577   .arc_name = "interface-output",
578   .node_name = "nsim-output-feature",
579   .runs_before = VNET_FEATURES ("interface-tx"),
580 };
581 /* *INDENT-ON */
582
583 /* *INDENT-OFF* */
584 VLIB_PLUGIN_REGISTER () =
585 {
586   .version = VPP_BUILD_VER,
587   .description = "Network Delay Simulator",
588 };
589 /* *INDENT-ON* */
590
591 static uword
592 unformat_delay (unformat_input_t * input, va_list * args)
593 {
594   f64 *result = va_arg (*args, f64 *);
595   f64 tmp;
596
597   if (unformat (input, "%f us", &tmp))
598     *result = tmp * 1e-6;
599   else if (unformat (input, "%f ms", &tmp))
600     *result = tmp * 1e-3;
601   else if (unformat (input, "%f sec", &tmp))
602     *result = tmp;
603   else
604     return 0;
605
606   return 1;
607 }
608
609 static uword
610 unformat_bandwidth (unformat_input_t * input, va_list * args)
611 {
612   f64 *result = va_arg (*args, f64 *);
613   f64 tmp;
614
615   if (unformat (input, "%f gbit", &tmp))
616     *result = tmp * 1e9;
617   else if (unformat (input, "%f gbyte", &tmp))
618     *result = tmp * 8e9;
619   else
620     return 0;
621   return 1;
622 }
623
624 static clib_error_t *
625 set_nsim_command_fn (vlib_main_t * vm,
626                      unformat_input_t * input, vlib_cli_command_t * cmd)
627 {
628   nsim_main_t *nsm = &nsim_main;
629   f64 delay, bandwidth;
630   f64 packet_size = 1500.0;
631   f64 drop_fraction = 0.0;
632   u32 packets_per_drop;
633   u32 num_workers = vlib_num_workers ();
634   int rv;
635
636   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
637     {
638       if (unformat (input, "delay %U", unformat_delay, &delay))
639         ;
640       else if (unformat (input, "bandwidth %U", unformat_bandwidth,
641                          &bandwidth))
642         ;
643       else if (unformat (input, "packet-size %f", &packet_size))
644         ;
645       else if (unformat (input, "packets-per-drop %d", &packets_per_drop))
646         {
647           if (packets_per_drop > 0)
648             drop_fraction = 1.0 / ((f64) packets_per_drop);
649         }
650       else if (unformat (input, "drop-fraction %f", &drop_fraction))
651         {
652           if (drop_fraction < 0.0 || drop_fraction > 1.0)
653             return clib_error_return
654               (0, "drop fraction must be between zero and 1");
655         }
656       else
657         break;
658     }
659
660   rv = nsim_configure (nsm, bandwidth, delay, packet_size, drop_fraction);
661
662   switch (rv)
663     {
664     case VNET_API_ERROR_INVALID_VALUE:
665       return clib_error_return (0, "invalid bandwidth %.2f", bandwidth);
666
667     case VNET_API_ERROR_INVALID_VALUE_2:
668       return clib_error_return (0, "invalid delay %.2f", delay);
669
670     case VNET_API_ERROR_INVALID_VALUE_3:
671       return clib_error_return (0, "invalid packet size %.2f", packet_size);
672
673     default:
674       return clib_error_return (0, "error %d", rv);
675
676     case 0:
677       break;
678     }
679
680   vlib_cli_output (vm, "Configured link delay %.2f ms, %.2f ms round-trip",
681                    nsm->delay * 1e3, 2.0 * nsm->delay * 1e3);
682   if (nsm->drop_fraction > 0.0)
683     vlib_cli_output (vm, "... simulating a network drop fraction of %.5f",
684                      nsm->drop_fraction);
685
686
687   if (num_workers)
688     vlib_cli_output (vm, "Sim uses %llu bytes per thread, %llu bytes total",
689                      nsm->mmap_size, nsm->mmap_size * num_workers);
690   else
691     vlib_cli_output (vm, "Sim uses %llu bytes total", nsm->mmap_size);
692
693   return 0;
694 }
695
696 /*?
697  * Configure the network simulation cross-connect
698  * Once the simulator is configured, use the "nsim enable-disable" command
699  * to set up a cross-connect with the supplied delay characteristics.
700  *
701  * The cross connect configuration may be changed without restarting vpp
702  * but it is good practice to shut down the interfaces.
703  *
704  * @cliexpar
705  * To configure the network delay simulator:
706  * @clistart
707  * set nsim delay 10.0 ms bandwidth 5.5 gbit packet-size 128
708  *
709  * @cliend
710  * @cliexcmd{set nsim delay <nn> bandwidth <bb> packet-size <nn>}
711 ?*/
712 /* *INDENT-OFF* */
713 VLIB_CLI_COMMAND (set_nsim_command, static) =
714 {
715   .path = "set nsim",
716   .short_help = "set nsim delay <time> bandwidth <bps> packet-size <nbytes>\n"
717   "    [packets-per-drop <nn>][drop-fraction <f64: 0.0 - 1.0>]",
718   .function = set_nsim_command_fn,
719 };
720 /* *INDENT-ON*/
721
722
723 static clib_error_t *
724 show_nsim_command_fn (vlib_main_t * vm,
725                       unformat_input_t * input, vlib_cli_command_t * cmd)
726 {
727   nsim_main_t *nsm = &nsim_main;
728   u32 num_workers = vlib_num_workers ();
729   int verbose = 0;
730
731   if (nsm->is_configured == 0)
732     return clib_error_return (0, "Network simulator not configured");
733
734   if (nsm->sw_if_index0 == 0)
735     return clib_error_return (0, "Network simulator not enabled");
736
737   if (unformat (input, "verbose"))
738     verbose = 1;
739
740   vlib_cli_output (vm, "Network simulator cross-connects %U and %U",
741                    format_vnet_sw_if_index_name,
742                    nsm->vnet_main, nsm->sw_if_index0,
743                    format_vnet_sw_if_index_name,
744                    nsm->vnet_main, nsm->sw_if_index1);
745
746   vlib_cli_output (vm,
747                    "...inserting link delay of %.2f ms, %.2f ms round-trip",
748                    nsm->delay * 1e3, 2.0 * nsm->delay * 1e3);
749
750   if (nsm->drop_fraction > 0.0)
751     vlib_cli_output (vm, "... simulating a network drop fraction of %.5f",
752                      nsm->drop_fraction);
753
754   if (verbose)
755     {
756
757       vlib_cli_output (vm, "  Configured bandwidth: %.2f gbit/sec",
758                        nsm->bandwidth / 1e9);
759       vlib_cli_output (vm, "  Configured packet size: %f", nsm->packet_size);
760       if (num_workers)
761         vlib_cli_output
762           (vm, "  Sim uses %llu bytes per thread, %llu bytes total",
763            nsm->mmap_size, nsm->mmap_size * num_workers);
764       else
765         vlib_cli_output (vm, "  Sim uses %llu bytes total", nsm->mmap_size);
766     }
767
768   return 0;
769 }
770
771 /*?
772  * Display state info for the network delay simulator.
773  *
774  * @cliexpar
775  * To display the state of the network simulator
776  * @clistart
777  * show nsim verbose
778  * Network simulator cross-connects TenGigabitEthernet2/0/0 and TenGigabitEthernet2/0/1
779  * ...inserting link delay of 10.00 ms, 20.00 ms round-trip
780  *  Configured bandwidth: 10.10 gbit/sec
781  *  Configured packet size: 128
782  *  Sim uses 157814784 bytes total
783  * @cliend
784  * @cliexcmd{show nsim}
785 ?*/
786
787 /* *INDENT-OFF* */
788 VLIB_CLI_COMMAND (show_nsim_command, static) =
789 {
790   .path = "show nsim",
791   .short_help = "Display network delay simulator configuration",
792   .function = show_nsim_command_fn,
793 };
794 /* *INDENT-ON* */
795
796 /*
797  * fd.io coding-style-patch-verification: ON
798  *
799  * Local Variables:
800  * eval: (c-set-style "gnu")
801  * End:
802  */