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