c6414905018ccbd689d4e60a140b55407409c162
[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   i = (!nsm->poll_main_thread && num_workers) ? 1 : 0;
186   for (; i < num_workers + 1; i++)
187     {
188       nsim_wheel_t *wp;
189
190       nsm->mmap_size = sizeof (nsim_wheel_t)
191         + wheel_slots_per_worker * sizeof (nsim_wheel_entry_t);
192
193       nsm->mmap_size += pagesize - 1;
194       nsm->mmap_size &= ~(pagesize - 1);
195
196       wp = clib_mem_vm_alloc (nsm->mmap_size);
197       ASSERT (wp != 0);
198       wp->wheel_size = wheel_slots_per_worker;
199       wp->cursize = 0;
200       wp->head = 0;
201       wp->tail = 0;
202       wp->entries = (void *) (wp + 1);
203       nsm->wheel_by_thread[i] = wp;
204     }
205
206   vlib_worker_thread_barrier_sync (vm);
207
208   /* turn on the ring scrapers */
209   i = (!nsm->poll_main_thread && num_workers) ? 1 : 0;
210   for (; i < num_workers + 1; i++)
211     {
212       vlib_main_t *this_vm = vlib_mains[i];
213
214       vlib_node_set_state (this_vm, nsim_input_node.index,
215                            VLIB_NODE_STATE_POLLING);
216     }
217
218   vlib_worker_thread_barrier_release (vm);
219
220   nsm->is_configured = 1;
221   return 0;
222 }
223
224 /*
225  * enable or disable the cross-connect
226  */
227 static clib_error_t *
228 nsim_cross_connect_enable_disable_command_fn (vlib_main_t * vm,
229                                               unformat_input_t * input,
230                                               vlib_cli_command_t * cmd)
231 {
232   nsim_main_t *nsm = &nsim_main;
233   unformat_input_t _line_input, *line_input = &_line_input;
234   u32 sw_if_index0 = ~0;
235   u32 sw_if_index1 = ~0;
236   int enable_disable = 1;
237   u32 tmp;
238   int rv;
239
240   /* Get a line of input. */
241   if (!unformat_user (input, unformat_line_input, line_input))
242     return 0;
243
244   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
245     {
246       if (unformat (line_input, "disable"))
247         enable_disable = 0;
248       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
249                          nsm->vnet_main, &tmp))
250         {
251           if (sw_if_index0 == ~0)
252             sw_if_index0 = tmp;
253           else
254             sw_if_index1 = tmp;
255         }
256       else
257         break;
258     }
259
260   unformat_free (line_input);
261
262   if (sw_if_index0 == ~0 || sw_if_index1 == ~0)
263     return clib_error_return (0, "Please specify two interfaces...");
264
265   rv = nsim_cross_connect_enable_disable (nsm, sw_if_index0,
266                                           sw_if_index1, enable_disable);
267
268   switch (rv)
269     {
270     case 0:
271       break;
272
273     case VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE:
274       return clib_error_return (0, "Not configured, please 'set nsim' first");
275
276     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
277       return clib_error_return
278         (0, "Invalid interface, only works on physical ports");
279       break;
280
281     case VNET_API_ERROR_UNIMPLEMENTED:
282       return clib_error_return (0,
283                                 "Device driver doesn't support redirection");
284       break;
285
286     default:
287       return clib_error_return (0, "nsim_enable_disable returned %d", rv);
288     }
289   return 0;
290 }
291
292 static clib_error_t *
293 nsim_config (vlib_main_t * vm, unformat_input_t * input)
294 {
295   nsim_main_t *nsm = &nsim_main;
296
297   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
298     {
299       if (unformat (input, "poll-main-thread"))
300         {
301           nsm->poll_main_thread = 1;
302         }
303       else
304         {
305           return clib_error_return (0, "unknown input '%U'",
306                                     format_unformat_error, input);
307         }
308     }
309   return 0;
310 }
311
312 VLIB_CONFIG_FUNCTION (nsim_config, "nsim");
313
314 /*?
315  * Enable or disable network simulation cross-connect on two interfaces
316  * The network simulator must have already been configured, see
317  * the "nsim_configure" command.
318  *
319  * Place the interfaces into a bridge group, to ensure that
320  * interfaces are in promiscuous mode.
321  *
322  * @cliexpar
323  * To enable or disable network simulation cross-connect
324  * @clistart
325  * nsim cross-connect enable-disable TenGigabitEthernet2/0/0 TenGigabitEthernet2/0
326  * nsim cross-connect enable-disable TenGigabitEthernet2/0/0 TenGigabitEthernet2/0 disable
327  * @cliend
328  * @cliexcmd{nsim enable-disable <intfc> <intfc> [disable]}
329 ?*/
330 /* *INDENT-OFF* */
331 VLIB_CLI_COMMAND (nsim_enable_disable_command, static) =
332 {
333   .path = "nsim cross-connect enable-disable",
334   .short_help =
335   "nsim cross-connect enable-disable <interface-name-1> "
336   "<interface-name-2> [disable]",
337   .function = nsim_cross_connect_enable_disable_command_fn,
338 };
339 /* *INDENT-ON* */
340
341 /* API message handler */
342 static void vl_api_nsim_cross_connect_enable_disable_t_handler
343   (vl_api_nsim_cross_connect_enable_disable_t * mp)
344 {
345   vl_api_nsim_cross_connect_enable_disable_reply_t *rmp;
346   nsim_main_t *nsm = &nsim_main;
347   int rv;
348   u32 sw_if_index0, sw_if_index1;
349
350   sw_if_index0 = clib_net_to_host_u32 (mp->sw_if_index0);
351   sw_if_index1 = clib_net_to_host_u32 (mp->sw_if_index1);
352
353   if (!vnet_sw_if_index_is_api_valid (sw_if_index0))
354     {
355       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
356       goto bad_sw_if_index;
357     }
358   if (!vnet_sw_if_index_is_api_valid (sw_if_index1))
359     {
360       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
361       goto bad_sw_if_index;
362     }
363
364   rv = nsim_cross_connect_enable_disable (nsm, sw_if_index0, sw_if_index1,
365                                           (int) (mp->enable_disable));
366
367   BAD_SW_IF_INDEX_LABEL;
368   REPLY_MACRO (VL_API_NSIM_CROSS_CONNECT_ENABLE_DISABLE_REPLY);
369 }
370
371 /* API message handler */
372 static void vl_api_nsim_output_feature_enable_disable_t_handler
373   (vl_api_nsim_output_feature_enable_disable_t * mp)
374 {
375   vl_api_nsim_output_feature_enable_disable_reply_t *rmp;
376   nsim_main_t *nsm = &nsim_main;
377   int rv;
378   VALIDATE_SW_IF_INDEX (mp);
379
380   rv = nsim_output_feature_enable_disable (nsm, ntohl (mp->sw_if_index),
381                                            (int) (mp->enable_disable));
382
383   BAD_SW_IF_INDEX_LABEL;
384   REPLY_MACRO (VL_API_NSIM_OUTPUT_FEATURE_ENABLE_DISABLE_REPLY);
385 }
386
387 /* API message handler */
388 static void
389 vl_api_nsim_configure_t_handler (vl_api_nsim_configure_t * mp)
390 {
391   vl_api_nsim_configure_reply_t *rmp;
392   nsim_main_t *nsm = &nsim_main;
393   f64 delay, bandwidth, packet_size, drop_fraction;
394   u32 packets_per_drop;
395   int rv;
396
397   delay = ((f64) (ntohl (mp->delay_in_usec))) * 1e-6;
398   bandwidth = (f64) (clib_net_to_host_u64 (mp->bandwidth_in_bits_per_second));
399   packet_size = (f64) (ntohl (mp->average_packet_size));
400
401   packets_per_drop = ntohl (mp->packets_per_drop);
402   if (packets_per_drop > 0)
403     drop_fraction = 1.0 / (f64) (packets_per_drop);
404   else
405     drop_fraction = 0.0;
406
407   rv = nsim_configure (nsm, bandwidth, delay, packet_size, drop_fraction);
408
409   REPLY_MACRO (VL_API_NSIM_CONFIGURE_REPLY);
410 }
411
412
413 /*
414  * enable or disable the output_feature
415  */
416 static clib_error_t *
417 nsim_output_feature_enable_disable_command_fn (vlib_main_t * vm,
418                                                unformat_input_t * input,
419                                                vlib_cli_command_t * cmd)
420 {
421   nsim_main_t *nsm = &nsim_main;
422   unformat_input_t _line_input, *line_input = &_line_input;
423   u32 sw_if_index = ~0;
424   int enable_disable = 1;
425   int rv;
426
427   /* Get a line of input. */
428   if (!unformat_user (input, unformat_line_input, line_input))
429     return 0;
430
431   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
432     {
433       if (unformat (line_input, "disable"))
434         enable_disable = 0;
435       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
436                          nsm->vnet_main, &sw_if_index))
437         ;
438       else
439         {
440           clib_error_t *error = clib_error_return (0, "unknown input `%U'",
441                                                    format_unformat_error,
442                                                    line_input);
443           unformat_free (line_input);
444           return error;
445         }
446     }
447
448   unformat_free (line_input);
449
450   if (sw_if_index == ~0)
451     return clib_error_return (0, "Please specify one interface...");
452
453   rv = nsim_output_feature_enable_disable (nsm, sw_if_index, enable_disable);
454
455   switch (rv)
456     {
457     case 0:
458       break;
459
460     case VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE:
461       return clib_error_return (0, "Not configured, please 'set nsim' first");
462
463     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
464       return clib_error_return
465         (0, "Invalid interface, only works on physical ports");
466       break;
467
468     case VNET_API_ERROR_UNIMPLEMENTED:
469       return clib_error_return (0,
470                                 "Device driver doesn't support redirection");
471       break;
472
473     default:
474       return clib_error_return
475         (0, "nsim_output_feature_enable_disable returned %d", rv);
476     }
477   return 0;
478 }
479
480 /*?
481  * Enable or disable network simulation output feature on an interface
482  * The network simulator must have already been configured, see
483  * the "nsim_configure" command.
484  *
485  * @cliexpar
486  * To enable or disable network simulation output feature
487  * @clistart
488  * nsim output-feature enable-disable TenGigabitEthernet2/0/0
489  * nsim output-feature enable-disable TenGigabitEthernet2/0/0 disable
490  * @cliend
491  * @cliexcmd{nsim output-feature enable-disable <intfc> [disable]}
492 ?*/
493 /* *INDENT-OFF* */
494 VLIB_CLI_COMMAND (nsim_output_feature_enable_disable_command, static) =
495 {
496   .path = "nsim output-feature enable-disable",
497   .short_help =
498   "nsim output-feature enable-disable <interface-name> [disable]",
499   .function = nsim_output_feature_enable_disable_command_fn,
500 };
501 /* *INDENT-ON* */
502
503 #include <nsim/nsim.api.c>
504 static clib_error_t *
505 nsim_init (vlib_main_t * vm)
506 {
507   nsim_main_t *nsm = &nsim_main;
508
509   nsm->vlib_main = vm;
510   nsm->vnet_main = vnet_get_main ();
511
512   /* Ask for a correctly-sized block of API message decode slots */
513   nsm->msg_id_base = setup_message_id_table ();
514
515   return 0;
516 }
517
518 VLIB_INIT_FUNCTION (nsim_init);
519
520 /* *INDENT-OFF* */
521 VNET_FEATURE_INIT (nsim, static) =
522 {
523   .arc_name = "device-input",
524   .node_name = "nsim",
525   .runs_before = VNET_FEATURES ("ethernet-input"),
526 };
527 /* *INDENT-ON */
528
529 /* *INDENT-OFF* */
530 VNET_FEATURE_INIT (nsim_feature, static) =
531 {
532   .arc_name = "interface-output",
533   .node_name = "nsim-output-feature",
534   .runs_before = VNET_FEATURES ("interface-tx"),
535 };
536 /* *INDENT-ON */
537
538 /* *INDENT-OFF* */
539 VLIB_PLUGIN_REGISTER () =
540 {
541   .version = VPP_BUILD_VER,
542   .description = "Network Delay Simulator",
543 };
544 /* *INDENT-ON* */
545
546 static uword
547 unformat_delay (unformat_input_t * input, va_list * args)
548 {
549   f64 *result = va_arg (*args, f64 *);
550   f64 tmp;
551
552   if (unformat (input, "%f us", &tmp))
553     *result = tmp * 1e-6;
554   else if (unformat (input, "%f ms", &tmp))
555     *result = tmp * 1e-3;
556   else if (unformat (input, "%f sec", &tmp))
557     *result = tmp;
558   else
559     return 0;
560
561   return 1;
562 }
563
564 static uword
565 unformat_bandwidth (unformat_input_t * input, va_list * args)
566 {
567   f64 *result = va_arg (*args, f64 *);
568   f64 tmp;
569
570   if (unformat (input, "%f gbit", &tmp))
571     *result = tmp * 1e9;
572   else if (unformat (input, "%f gbyte", &tmp))
573     *result = tmp * 8e9;
574   else
575     return 0;
576   return 1;
577 }
578
579 static clib_error_t *
580 set_nsim_command_fn (vlib_main_t * vm,
581                      unformat_input_t * input, vlib_cli_command_t * cmd)
582 {
583   nsim_main_t *nsm = &nsim_main;
584   f64 delay, bandwidth;
585   f64 packet_size = 1500.0;
586   f64 drop_fraction = 0.0;
587   u32 packets_per_drop;
588   u32 num_workers = vlib_num_workers ();
589   int rv;
590
591   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
592     {
593       if (unformat (input, "delay %U", unformat_delay, &delay))
594         ;
595       else if (unformat (input, "bandwidth %U", unformat_bandwidth,
596                          &bandwidth))
597         ;
598       else if (unformat (input, "packet-size %f", &packet_size))
599         ;
600       else if (unformat (input, "packets-per-drop %d", &packets_per_drop))
601         {
602           if (packets_per_drop > 0)
603             drop_fraction = 1.0 / ((f64) packets_per_drop);
604         }
605       else if (unformat (input, "drop-fraction %f", &drop_fraction))
606         {
607           if (drop_fraction < 0.0 || drop_fraction > 1.0)
608             return clib_error_return
609               (0, "drop fraction must be between zero and 1");
610         }
611       else if (unformat (input, "poll-main-thread"))
612         nsm->poll_main_thread = 1;
613       else
614         break;
615     }
616
617   rv = nsim_configure (nsm, bandwidth, delay, packet_size, drop_fraction);
618
619   switch (rv)
620     {
621     case VNET_API_ERROR_INVALID_VALUE:
622       return clib_error_return (0, "invalid bandwidth %.2f", bandwidth);
623
624     case VNET_API_ERROR_INVALID_VALUE_2:
625       return clib_error_return (0, "invalid delay %.2f", delay);
626
627     case VNET_API_ERROR_INVALID_VALUE_3:
628       return clib_error_return (0, "invalid packet size %.2f", packet_size);
629
630     default:
631       return clib_error_return (0, "error %d", rv);
632
633     case 0:
634       break;
635     }
636
637   vlib_cli_output (vm, "Configured link delay %.2f ms, %.2f ms round-trip",
638                    nsm->delay * 1e3, 2.0 * nsm->delay * 1e3);
639   if (nsm->drop_fraction > 0.0)
640     vlib_cli_output (vm, "... simulating a network drop fraction of %.5f",
641                      nsm->drop_fraction);
642
643
644   if (num_workers)
645     vlib_cli_output (vm, "Sim uses %llu bytes per thread, %llu bytes total",
646                      nsm->mmap_size, nsm->mmap_size * num_workers);
647   else
648     vlib_cli_output (vm, "Sim uses %llu bytes total", nsm->mmap_size);
649
650   return 0;
651 }
652
653 /*?
654  * Configure the network simulation cross-connect
655  * Once the simulator is configured, use the "nsim enable-disable" command
656  * to set up a cross-connect with the supplied delay characteristics.
657  *
658  * The cross connect configuration may be changed without restarting vpp
659  * but it is good practice to shut down the interfaces.
660  *
661  * @cliexpar
662  * To configure the network delay simulator:
663  * @clistart
664  * set nsim delay 10.0 ms bandwidth 5.5 gbit packet-size 128
665  *
666  * @cliend
667  * @cliexcmd{set nsim delay <nn> bandwidth <bb> packet-size <nn>}
668 ?*/
669 /* *INDENT-OFF* */
670 VLIB_CLI_COMMAND (set_nsim_command, static) =
671 {
672   .path = "set nsim",
673   .short_help = "set nsim delay <time> bandwidth <bps> packet-size <nbytes>\n"
674   "    [packets-per-drop <nn>][drop-fraction <f64: 0.0 - 1.0>]",
675   .function = set_nsim_command_fn,
676 };
677 /* *INDENT-ON*/
678
679
680 static clib_error_t *
681 show_nsim_command_fn (vlib_main_t * vm,
682                       unformat_input_t * input, vlib_cli_command_t * cmd)
683 {
684   nsim_main_t *nsm = &nsim_main;
685   u32 num_workers = vlib_num_workers ();
686   int verbose = 0;
687
688   if (nsm->is_configured == 0)
689     return clib_error_return (0, "Network simulator not configured");
690
691   if (nsm->sw_if_index0 == 0)
692     return clib_error_return (0, "Network simulator not enabled");
693
694   if (unformat (input, "verbose"))
695     verbose = 1;
696
697   vlib_cli_output (vm, "Network simulator cross-connects %U and %U",
698                    format_vnet_sw_if_index_name,
699                    nsm->vnet_main, nsm->sw_if_index0,
700                    format_vnet_sw_if_index_name,
701                    nsm->vnet_main, nsm->sw_if_index1);
702
703   vlib_cli_output (vm,
704                    "...inserting link delay of %.2f ms, %.2f ms round-trip",
705                    nsm->delay * 1e3, 2.0 * nsm->delay * 1e3);
706
707   if (nsm->drop_fraction > 0.0)
708     vlib_cli_output (vm, "... simulating a network drop fraction of %.5f",
709                      nsm->drop_fraction);
710
711   if (verbose)
712     {
713
714       vlib_cli_output (vm, "  Configured bandwidth: %.2f gbit/sec",
715                        nsm->bandwidth / 1e9);
716       vlib_cli_output (vm, "  Configured packet size: %f", nsm->packet_size);
717       if (num_workers)
718         vlib_cli_output
719           (vm, "  Sim uses %llu bytes per thread, %llu bytes total",
720            nsm->mmap_size, nsm->mmap_size * num_workers);
721       else
722         vlib_cli_output (vm, "  Sim uses %llu bytes total", nsm->mmap_size);
723     }
724
725   return 0;
726 }
727
728 /*?
729  * Display state info for the network delay simulator.
730  *
731  * @cliexpar
732  * To display the state of the network simulator
733  * @clistart
734  * show nsim verbose
735  * Network simulator cross-connects TenGigabitEthernet2/0/0 and TenGigabitEthernet2/0/1
736  * ...inserting link delay of 10.00 ms, 20.00 ms round-trip
737  *  Configured bandwidth: 10.10 gbit/sec
738  *  Configured packet size: 128
739  *  Sim uses 157814784 bytes total
740  * @cliend
741  * @cliexcmd{show nsim}
742 ?*/
743
744 /* *INDENT-OFF* */
745 VLIB_CLI_COMMAND (show_nsim_command, static) =
746 {
747   .path = "show nsim",
748   .short_help = "Display network delay simulator configuration",
749   .function = show_nsim_command_fn,
750 };
751 /* *INDENT-ON* */
752
753 /*
754  * fd.io coding-style-patch-verification: ON
755  *
756  * Local Variables:
757  * eval: (c-set-style "gnu")
758  * End:
759  */