Make the loss / delay sim available as an output feature
[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 = (u32) ((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
352   rv = nsim_cross_connect_enable_disable (nsm, ntohl (mp->sw_if_index0),
353                                           ntohl (mp->sw_if_index1),
354                                           (int) (mp->enable_disable));
355
356   REPLY_MACRO (VL_API_NSIM_CROSS_CONNECT_ENABLE_DISABLE_REPLY);
357 }
358
359 /* API message handler */
360 static void vl_api_nsim_output_feature_enable_disable_t_handler
361   (vl_api_nsim_output_feature_enable_disable_t * mp)
362 {
363   vl_api_nsim_output_feature_enable_disable_reply_t *rmp;
364   nsim_main_t *nsm = &nsim_main;
365   int rv;
366
367   rv = nsim_output_feature_enable_disable (nsm, ntohl (mp->sw_if_index),
368                                            (int) (mp->enable_disable));
369
370   REPLY_MACRO (VL_API_NSIM_OUTPUT_FEATURE_ENABLE_DISABLE_REPLY);
371 }
372
373 /* API message handler */
374 static void
375 vl_api_nsim_configure_t_handler (vl_api_nsim_configure_t * mp)
376 {
377   vl_api_nsim_configure_reply_t *rmp;
378   nsim_main_t *nsm = &nsim_main;
379   f64 delay, bandwidth, packet_size, drop_fraction;
380   u32 packets_per_drop;
381   int rv;
382
383   delay = ((f64) (ntohl (mp->delay_in_usec))) * 1e-6;
384   bandwidth = (f64) (clib_net_to_host_u64 (mp->bandwidth_in_bits_per_second));
385   packet_size = (f64) (ntohl (mp->average_packet_size));
386
387   packets_per_drop = ntohl (mp->packets_per_drop);
388   if (packets_per_drop > 0)
389     drop_fraction = 1.0 / (f64) (packets_per_drop);
390   else
391     drop_fraction = 0.0;
392
393   rv = nsim_configure (nsm, bandwidth, delay, packet_size, drop_fraction);
394
395   REPLY_MACRO (VL_API_NSIM_CONFIGURE_REPLY);
396 }
397
398
399 /*
400  * enable or disable the output_feature
401  */
402 static clib_error_t *
403 nsim_output_feature_enable_disable_command_fn (vlib_main_t * vm,
404                                                unformat_input_t * input,
405                                                vlib_cli_command_t * cmd)
406 {
407   nsim_main_t *nsm = &nsim_main;
408   unformat_input_t _line_input, *line_input = &_line_input;
409   u32 sw_if_index = ~0;
410   int enable_disable = 1;
411   int rv;
412
413   /* Get a line of input. */
414   if (!unformat_user (input, unformat_line_input, line_input))
415     return 0;
416
417   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
418     {
419       if (unformat (line_input, "disable"))
420         enable_disable = 0;
421       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
422                          nsm->vnet_main, &sw_if_index))
423         ;
424       else
425         {
426           clib_error_t *error = clib_error_return (0, "unknown input `%U'",
427                                                    format_unformat_error,
428                                                    line_input);
429           unformat_free (line_input);
430           return error;
431         }
432     }
433
434   unformat_free (line_input);
435
436   if (sw_if_index == ~0)
437     return clib_error_return (0, "Please specify one interface...");
438
439   rv = nsim_output_feature_enable_disable (nsm, sw_if_index, enable_disable);
440
441   switch (rv)
442     {
443     case 0:
444       break;
445
446     case VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE:
447       return clib_error_return (0, "Not configured, please 'set nsim' first");
448
449     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
450       return clib_error_return
451         (0, "Invalid interface, only works on physical ports");
452       break;
453
454     case VNET_API_ERROR_UNIMPLEMENTED:
455       return clib_error_return (0,
456                                 "Device driver doesn't support redirection");
457       break;
458
459     default:
460       return clib_error_return
461         (0, "nsim_output_feature_enable_disable returned %d", rv);
462     }
463   return 0;
464 }
465
466 /*?
467  * Enable or disable network simulation output feature on an interface
468  * The network simulator must have already been configured, see
469  * the "nsim_configure" command.
470  *
471  * @cliexpar
472  * To enable or disable network simulation output feature
473  * @clistart
474  * nsim output-feature enable-disable TenGigabitEthernet2/0/0
475  * nsim output-feature enable-disable TenGigabitEthernet2/0/0 disable
476  * @cliend
477  * @cliexcmd{nsim output-feature enable-disable <intfc> [disable]}
478 ?*/
479 /* *INDENT-OFF* */
480 VLIB_CLI_COMMAND (nsim_output_feature_enable_disable_command, static) =
481 {
482   .path = "nsim output-feature enable-disable",
483   .short_help =
484   "nsim output-feature enable-disable <interface-name> [disable]",
485   .function = nsim_output_feature_enable_disable_command_fn,
486 };
487 /* *INDENT-ON* */
488
489 /* Set up the API message handling tables */
490 static clib_error_t *
491 nsim_plugin_api_hookup (vlib_main_t * vm)
492 {
493   nsim_main_t *nsm = &nsim_main;
494 #define _(N,n)                                                  \
495     vl_msg_api_set_handlers((VL_API_##N + nsm->msg_id_base),     \
496                            #n,                                  \
497                            vl_api_##n##_t_handler,              \
498                            vl_noop_handler,                     \
499                            vl_api_##n##_t_endian,               \
500                            vl_api_##n##_t_print,                \
501                            sizeof(vl_api_##n##_t), 1);
502   foreach_nsim_plugin_api_msg;
503 #undef _
504
505   return 0;
506 }
507
508 #define vl_msg_name_crc_list
509 #include <nsim/nsim_all_api_h.h>
510 #undef vl_msg_name_crc_list
511
512 static void
513 setup_message_id_table (nsim_main_t * nsm, api_main_t * am)
514 {
515 #define _(id,n,crc)   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nsm->msg_id_base);
516   foreach_vl_msg_name_crc_nsim;
517 #undef _
518 }
519
520 static clib_error_t *
521 nsim_init (vlib_main_t * vm)
522 {
523   nsim_main_t *nsm = &nsim_main;
524   clib_error_t *error = 0;
525   u8 *name;
526
527   nsm->vlib_main = vm;
528   nsm->vnet_main = vnet_get_main ();
529
530   name = format (0, "nsim_%08x%c", api_version, 0);
531
532   /* Ask for a correctly-sized block of API message decode slots */
533   nsm->msg_id_base = vl_msg_api_get_msg_ids
534     ((char *) name, VL_MSG_FIRST_AVAILABLE);
535
536   error = nsim_plugin_api_hookup (vm);
537
538   /* Add our API messages to the global name_crc hash table */
539   setup_message_id_table (nsm, &api_main);
540
541   vec_free (name);
542
543   return error;
544 }
545
546 VLIB_INIT_FUNCTION (nsim_init);
547
548 /* *INDENT-OFF* */
549 VNET_FEATURE_INIT (nsim, static) =
550 {
551   .arc_name = "device-input",
552   .node_name = "nsim",
553   .runs_before = VNET_FEATURES ("ethernet-input"),
554 };
555 /* *INDENT-ON */
556
557 /* *INDENT-OFF* */
558 VNET_FEATURE_INIT (nsim_feature, static) =
559 {
560   .arc_name = "interface-output",
561   .node_name = "nsim-output-feature",
562   .runs_before = VNET_FEATURES ("interface-tx"),
563 };
564 /* *INDENT-ON */
565
566 /* *INDENT-OFF* */
567 VLIB_PLUGIN_REGISTER () =
568 {
569   .version = VPP_BUILD_VER,
570   .description = "network delay simulator plugin",
571 };
572 /* *INDENT-ON* */
573
574 static uword
575 unformat_delay (unformat_input_t * input, va_list * args)
576 {
577   f64 *result = va_arg (*args, f64 *);
578   f64 tmp;
579
580   if (unformat (input, "%f us", &tmp))
581     *result = tmp * 1e-6;
582   else if (unformat (input, "%f ms", &tmp))
583     *result = tmp * 1e-3;
584   else if (unformat (input, "%f sec", &tmp))
585     *result = tmp;
586   else
587     return 0;
588
589   return 1;
590 }
591
592 static uword
593 unformat_bandwidth (unformat_input_t * input, va_list * args)
594 {
595   f64 *result = va_arg (*args, f64 *);
596   f64 tmp;
597
598   if (unformat (input, "%f gbit", &tmp))
599     *result = tmp * 1e9;
600   else if (unformat (input, "%f gbyte", &tmp))
601     *result = tmp * 8e9;
602   else
603     return 0;
604   return 1;
605 }
606
607 static clib_error_t *
608 set_nsim_command_fn (vlib_main_t * vm,
609                      unformat_input_t * input, vlib_cli_command_t * cmd)
610 {
611   nsim_main_t *nsm = &nsim_main;
612   f64 delay, bandwidth;
613   f64 packet_size = 1500.0;
614   f64 drop_fraction = 0.0;
615   u32 packets_per_drop;
616   u32 num_workers = vlib_num_workers ();
617   int rv;
618
619   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
620     {
621       if (unformat (input, "delay %U", unformat_delay, &delay))
622         ;
623       else if (unformat (input, "bandwidth %U", unformat_bandwidth,
624                          &bandwidth))
625         ;
626       else if (unformat (input, "packet-size %f", &packet_size))
627         ;
628       else if (unformat (input, "packets-per-drop %d", &packets_per_drop))
629         {
630           if (packets_per_drop > 0)
631             drop_fraction = 1.0 / ((f64) packets_per_drop);
632         }
633       else if (unformat (input, "drop-fraction %f", &drop_fraction))
634         {
635           if (drop_fraction < 0.0 || drop_fraction > 1.0)
636             return clib_error_return
637               (0, "drop fraction must be between zero and 1");
638         }
639       else
640         break;
641     }
642
643   rv = nsim_configure (nsm, bandwidth, delay, packet_size, drop_fraction);
644
645   switch (rv)
646     {
647     case VNET_API_ERROR_INVALID_VALUE:
648       return clib_error_return (0, "invalid bandwidth %.2f", bandwidth);
649
650     case VNET_API_ERROR_INVALID_VALUE_2:
651       return clib_error_return (0, "invalid delay %.2f", delay);
652
653     case VNET_API_ERROR_INVALID_VALUE_3:
654       return clib_error_return (0, "invalid packet size %.2f", packet_size);
655
656     default:
657       return clib_error_return (0, "error %d", rv);
658
659     case 0:
660       break;
661     }
662
663   vlib_cli_output (vm, "Configured link delay %.2f ms, %.2f ms round-trip",
664                    nsm->delay * 1e3, 2.0 * nsm->delay * 1e3);
665   if (nsm->drop_fraction > 0.0)
666     vlib_cli_output (vm, "... simulating a network drop fraction of %.5f",
667                      nsm->drop_fraction);
668
669
670   if (num_workers)
671     vlib_cli_output (vm, "Sim uses %llu bytes per thread, %llu bytes total",
672                      nsm->mmap_size, nsm->mmap_size * num_workers);
673   else
674     vlib_cli_output (vm, "Sim uses %llu bytes total", nsm->mmap_size);
675
676   return 0;
677 }
678
679 /*?
680  * Configure the network simulation cross-connect
681  * Once the simulator is configured, use the "nsim enable-disable" command
682  * to set up a cross-connect with the supplied delay characteristics.
683  *
684  * The cross connect configuration may be changed without restarting vpp
685  * but it is good practice to shut down the interfaces.
686  *
687  * @cliexpar
688  * To configure the network delay simulator:
689  * @clistart
690  * set nsim delay 10.0 ms bandwidth 5.5 gbit packet-size 128
691  *
692  * @cliend
693  * @cliexcmd{set nsim delay <nn> bandwidth <bb> packet-size <nn>}
694 ?*/
695 /* *INDENT-OFF* */
696 VLIB_CLI_COMMAND (set_nsim_command, static) =
697 {
698   .path = "set nsim",
699   .short_help = "set nsim delay <time> bandwidth <bps> packet-size <nbytes>\n"
700   "    [packets-per-drop <nn>][drop-fraction <f64: 0.0 - 1.0>]",
701   .function = set_nsim_command_fn,
702 };
703 /* *INDENT-ON*/
704
705
706 static clib_error_t *
707 show_nsim_command_fn (vlib_main_t * vm,
708                       unformat_input_t * input, vlib_cli_command_t * cmd)
709 {
710   nsim_main_t *nsm = &nsim_main;
711   u32 num_workers = vlib_num_workers ();
712   int verbose = 0;
713
714   if (nsm->is_configured == 0)
715     return clib_error_return (0, "Network simulator not configured");
716
717   if (nsm->sw_if_index0 == 0)
718     return clib_error_return (0, "Network simulator not enabled");
719
720   if (unformat (input, "verbose"))
721     verbose = 1;
722
723   vlib_cli_output (vm, "Network simulator cross-connects %U and %U",
724                    format_vnet_sw_if_index_name,
725                    nsm->vnet_main, nsm->sw_if_index0,
726                    format_vnet_sw_if_index_name,
727                    nsm->vnet_main, nsm->sw_if_index1);
728
729   vlib_cli_output (vm,
730                    "...inserting link delay of %.2f ms, %.2f ms round-trip",
731                    nsm->delay * 1e3, 2.0 * nsm->delay * 1e3);
732
733   if (nsm->drop_fraction > 0.0)
734     vlib_cli_output (vm, "... simulating a network drop fraction of %.5f",
735                      nsm->drop_fraction);
736
737   if (verbose)
738     {
739
740       vlib_cli_output (vm, "  Configured bandwidth: %.2f gbit/sec",
741                        nsm->bandwidth / 1e9);
742       vlib_cli_output (vm, "  Configured packet size: %f", nsm->packet_size);
743       if (num_workers)
744         vlib_cli_output
745           (vm, "  Sim uses %llu bytes per thread, %llu bytes total",
746            nsm->mmap_size, nsm->mmap_size * num_workers);
747       else
748         vlib_cli_output (vm, "  Sim uses %llu bytes total", nsm->mmap_size);
749     }
750
751   return 0;
752 }
753
754 /*?
755  * Display state info for the network delay simulator.
756  *
757  * @cliexpar
758  * To display the state of the network simulator
759  * @clistart
760  * show nsim verbose
761  * Network simulator cross-connects TenGigabitEthernet2/0/0 and TenGigabitEthernet2/0/1
762  * ...inserting link delay of 10.00 ms, 20.00 ms round-trip
763  *  Configured bandwidth: 10.10 gbit/sec
764  *  Configured packet size: 128
765  *  Sim uses 157814784 bytes total
766  * @cliend
767  * @cliexcmd{show nsim}
768 ?*/
769
770 /* *INDENT-OFF* */
771 VLIB_CLI_COMMAND (show_nsim_command, static) =
772 {
773   .path = "show nsim",
774   .short_help = "Display network delay simulator configuration",
775   .function = show_nsim_command_fn,
776 };
777 /* *INDENT-ON* */
778
779 /*
780  * fd.io coding-style-patch-verification: ON
781  *
782  * Local Variables:
783  * eval: (c-set-style "gnu")
784  * End:
785  */