Mark some show commands as mp safe
[vpp.git] / vnet / vnet / devices / dpdk / cli.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vnet/vnet.h>
16 #include <vppinfra/vec.h>
17 #include <vppinfra/error.h>
18 #include <vppinfra/format.h>
19 #include <vppinfra/xxhash.h>
20
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/devices/dpdk/dpdk.h>
23 #include <vnet/classify/vnet_classify.h>
24 #include <vnet/mpls-gre/packet.h>
25
26 #include "dpdk_priv.h"
27
28 frame_queue_trace_t *frame_queue_traces;
29
30 static clib_error_t *
31 pcap_trace_command_fn (vlib_main_t * vm,
32      unformat_input_t * input,
33      vlib_cli_command_t * cmd)
34 {
35   dpdk_main_t * dm = &dpdk_main;
36   u8 * filename;
37   u32 max;
38   int matched = 0;
39   clib_error_t * error = 0;
40
41   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
42     {
43       if (unformat (input, "on"))
44         {
45           if (dm->tx_pcap_enable == 0)
46             {
47               if (dm->pcap_filename == 0)
48                 dm->pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
49
50               memset (&dm->pcap_main, 0, sizeof (dm->pcap_main));
51               dm->pcap_main.file_name = (char *) dm->pcap_filename;
52               dm->pcap_main.n_packets_to_capture = 100;
53               if (dm->pcap_pkts_to_capture)
54                 dm->pcap_main.n_packets_to_capture = dm->pcap_pkts_to_capture;
55
56               dm->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
57               dm->tx_pcap_enable = 1;
58               matched = 1;
59               vlib_cli_output (vm, "pcap tx capture on...");
60             }
61           else
62             {
63               vlib_cli_output (vm, "pcap tx capture already on...");
64             }
65           matched = 1;
66         }
67       else if (unformat (input, "off"))
68         {
69           if (dm->tx_pcap_enable)
70             {
71               vlib_cli_output (vm, "captured %d pkts...",
72                                dm->pcap_main.n_packets_captured+1);
73               if (dm->pcap_main.n_packets_captured)
74                 {
75                   dm->pcap_main.n_packets_to_capture =
76                     dm->pcap_main.n_packets_captured;
77                   error = pcap_write (&dm->pcap_main);
78                   if (error)
79                     clib_error_report (error);
80                   else
81                     vlib_cli_output (vm, "saved to %s...", dm->pcap_filename);
82                 }
83             }
84           else
85             {
86               vlib_cli_output (vm, "pcap tx capture already off...");
87             }
88
89           dm->tx_pcap_enable = 0;
90           matched = 1;
91         }
92       else if (unformat (input, "max %d", &max))
93         {
94           dm->pcap_pkts_to_capture = max;
95           matched = 1;
96         }
97
98       else if (unformat (input, "intfc %U",
99                          unformat_vnet_sw_interface, dm->vnet_main,
100                          &dm->pcap_sw_if_index))
101         matched = 1;
102       else if (unformat (input, "intfc any"))
103         {
104           dm->pcap_sw_if_index = 0;
105           matched = 1;
106         }
107       else if (unformat (input, "file %s", &filename))
108         {
109           u8 * chroot_filename;
110           /* Brain-police user path input */
111           if (strstr((char *)filename, "..") || index((char *)filename, '/'))
112             {
113               vlib_cli_output (vm, "illegal characters in filename '%s'",
114                                filename);
115               continue;
116             }
117
118           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
119           vec_free (filename);
120
121           if (dm->pcap_filename)
122             vec_free (dm->pcap_filename);
123           vec_add1 (filename, 0);
124           dm->pcap_filename = chroot_filename;
125           matched = 1;
126         }
127       else if (unformat (input, "status"))
128         {
129           if (dm->tx_pcap_enable == 0)
130             {
131               vlib_cli_output (vm, "pcap tx capture is off...");
132               continue;
133             }
134
135           vlib_cli_output (vm, "pcap tx capture: %d of %d pkts...",
136                            dm->pcap_main.n_packets_captured,
137                            dm->pcap_main.n_packets_to_capture);
138           matched = 1;
139         }
140
141       else
142         break;
143     }
144
145   if (matched == 0)
146     return clib_error_return (0, "unknown input `%U'",
147                               format_unformat_error, input);
148
149   return 0;
150 }
151
152 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
153     .path = "pcap tx trace",
154     .short_help =
155     "pcap tx trace on off max <nn> intfc <intfc> file <name> status",
156     .function = pcap_trace_command_fn,
157 };
158
159
160 static clib_error_t *
161 show_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
162                  vlib_cli_command_t * cmd)
163 {
164   struct rte_mempool * rmp;
165   int i;
166
167   for(i = 0; i < vec_len(vm->buffer_main->pktmbuf_pools); i++)
168     {
169       rmp = vm->buffer_main->pktmbuf_pools[i];
170       if (rmp)
171         {
172           unsigned count = rte_mempool_count(rmp);
173           unsigned free_count = rte_mempool_free_count(rmp);
174
175           vlib_cli_output(vm, "name=\"%s\"  available = %7d allocated = %7d total = %7d\n",
176                           rmp->name, (u32)count, (u32)free_count,
177                           (u32)(count+free_count));
178         }
179       else
180         {
181            vlib_cli_output(vm, "rte_mempool is NULL (!)\n");
182         }
183     }
184   return 0;
185 }
186
187 VLIB_CLI_COMMAND (cmd_show_dpdk_bufferr,static) = {
188     .path = "show dpdk buffer",
189     .short_help = "show dpdk buffer state",
190     .function = show_dpdk_buffer,
191     .is_mp_safe = 1,
192 };
193
194 static clib_error_t *
195 test_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
196                  vlib_cli_command_t * cmd)
197 {
198   static u32 * allocated_buffers;
199   u32 n_alloc = 0;
200   u32 n_free = 0;
201   u32 first, actual_alloc;
202
203   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
204     {
205       if (unformat (input, "allocate %d", &n_alloc))
206         ;
207       else if (unformat (input, "free %d", &n_free))
208         ;
209       else
210         break;
211     }
212
213   if (n_free)
214     {
215       if (vec_len (allocated_buffers) < n_free)
216         return clib_error_return (0, "Can't free %d, only %d allocated",
217                                   n_free, vec_len (allocated_buffers));
218
219       first = vec_len(allocated_buffers) - n_free;
220       vlib_buffer_free (vm, allocated_buffers + first, n_free);
221       _vec_len (allocated_buffers) = first;
222     }
223   if (n_alloc)
224     {
225       first = vec_len (allocated_buffers);
226       vec_validate (allocated_buffers,
227                     vec_len (allocated_buffers) + n_alloc - 1);
228
229       actual_alloc = vlib_buffer_alloc (vm, allocated_buffers + first,
230                                         n_alloc);
231       _vec_len (allocated_buffers) = first + actual_alloc;
232
233       if (actual_alloc < n_alloc)
234         vlib_cli_output (vm, "WARNING: only allocated %d buffers",
235                          actual_alloc);
236     }
237
238   vlib_cli_output (vm, "Currently %d buffers allocated",
239                    vec_len (allocated_buffers));
240
241   if (allocated_buffers && vec_len(allocated_buffers) == 0)
242     vec_free(allocated_buffers);
243
244   return 0;
245 }
246
247 VLIB_CLI_COMMAND (cmd_test_dpdk_buffer,static) = {
248     .path = "test dpdk buffer",
249     .short_help = "test dpdk buffer [allocate <nn>][free <nn>]",
250     .function = test_dpdk_buffer,
251     .is_mp_safe = 1,
252 };
253
254 static void
255 show_dpdk_device_stats (vlib_main_t * vm, dpdk_device_t * xd)
256 {
257     vlib_cli_output(vm,
258                     "device_index %d\n"
259                     "  last_burst_sz           %d\n"
260                     "  max_burst_sz            %d\n"
261                     "  full_frames_cnt         %u\n"
262                     "  consec_full_frames_cnt  %u\n"
263                     "  congestion_cnt          %d\n"
264                     "  last_poll_time          %llu\n"
265                     "  max_poll_delay          %llu\n"
266                     "  discard_cnt             %u\n"
267                     "  total_packet_cnt        %u\n",
268                     xd->device_index,
269                     xd->efd_agent.last_burst_sz,
270                     xd->efd_agent.max_burst_sz,
271                     xd->efd_agent.full_frames_cnt,
272                     xd->efd_agent.consec_full_frames_cnt,
273                     xd->efd_agent.congestion_cnt,
274                     xd->efd_agent.last_poll_time,
275                     xd->efd_agent.max_poll_delay,
276                     xd->efd_agent.discard_cnt,
277                     xd->efd_agent.total_packet_cnt);
278
279     u32 device_queue_sz = rte_eth_rx_queue_count(xd->device_index,
280                                                  0 /* queue_id */);
281     vlib_cli_output(vm,
282                     "  device_queue_sz         %u\n",
283                     device_queue_sz);
284 }
285
286
287 /*
288  * Trigger threads to grab frame queue trace data
289  */
290 static clib_error_t *
291 trace_frame_queue (vlib_main_t *vm, unformat_input_t *input,
292                   vlib_cli_command_t *cmd)
293 {
294   clib_error_t * error = NULL;
295   frame_queue_trace_t *fqt;
296   u32 num_fq;
297   u32 fqix;
298   u32 enable = 0;
299
300   if (unformat(input, "on")) {
301     enable = 1;
302   } else if (unformat(input, "off")) {
303     enable = 0;
304   } else {
305       return clib_error_return(0, "expecting on or off");
306   }
307
308   num_fq = vec_len(vlib_frame_queues);
309   if (num_fq == 0)
310     {
311       vlib_cli_output(vm, "No frame queues exist\n");
312       return error;
313     }
314
315   // Allocate storage for trace if necessary
316   vec_validate_aligned(frame_queue_traces, num_fq-1, CLIB_CACHE_LINE_BYTES);
317
318   for (fqix=0; fqix<num_fq; fqix++) {
319     fqt = &frame_queue_traces[fqix];
320
321     memset(fqt->n_vectors, 0xff, sizeof(fqt->n_vectors));
322     fqt->written = 0;
323     vlib_frame_queues[fqix]->trace = enable;
324   }
325   return error;
326 }
327
328 VLIB_CLI_COMMAND (cmd_trace_frame_queue,static) = {
329     .path = "trace frame-queue",
330     .short_help = "trace frame-queue (on|off)",
331     .function = trace_frame_queue,
332     .is_mp_safe = 1,
333 };
334
335
336 /*
337  * Display frame queue trace data gathered by threads.
338  */
339 static clib_error_t *
340 show_frame_queue (vlib_main_t *vm, unformat_input_t *input,
341                   vlib_cli_command_t *cmd)
342 {
343   clib_error_t * error = NULL;
344   frame_queue_trace_t *fqt;
345   u32 num_fq;
346   u32 fqix;
347
348   num_fq = vec_len(frame_queue_traces);
349   if (num_fq == 0)
350     {
351       vlib_cli_output(vm, "No trace data for frame queues\n");
352       return error;
353     }
354
355   for (fqix=0; fqix<num_fq; fqix++) {
356     fqt = &frame_queue_traces[fqix];
357
358     vlib_cli_output(vm, "Thread %d %v\n", fqix, vlib_worker_threads[fqix].name);
359
360     if (fqt->written == 0)
361       {
362         vlib_cli_output(vm, "  no trace data\n");
363         continue;
364       }
365
366     vlib_cli_output(vm, "  vector-threshold %d  ring size %d  in use %d\n",
367                     fqt->threshold, fqt->nelts, fqt->n_in_use);
368     vlib_cli_output(vm, "  head %12d  head_hint %12d  tail %12d\n",
369                     fqt->head, fqt->head_hint, fqt->tail);
370     vlib_cli_output(vm, "  %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
371                     fqt->n_vectors[0], fqt->n_vectors[1], fqt->n_vectors[2], fqt->n_vectors[3],
372                     fqt->n_vectors[4], fqt->n_vectors[5], fqt->n_vectors[6], fqt->n_vectors[7],
373                     fqt->n_vectors[8], fqt->n_vectors[9], fqt->n_vectors[10], fqt->n_vectors[11],
374                     fqt->n_vectors[12], fqt->n_vectors[13], fqt->n_vectors[14], fqt->n_vectors[15]);
375
376     if (fqt->nelts > 16)
377       {
378         vlib_cli_output(vm, "  %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
379                         fqt->n_vectors[16], fqt->n_vectors[17], fqt->n_vectors[18], fqt->n_vectors[19],
380                         fqt->n_vectors[20], fqt->n_vectors[21], fqt->n_vectors[22], fqt->n_vectors[23],
381                         fqt->n_vectors[24], fqt->n_vectors[25], fqt->n_vectors[26], fqt->n_vectors[27],
382                         fqt->n_vectors[28], fqt->n_vectors[29], fqt->n_vectors[30], fqt->n_vectors[31]);
383       }
384   }
385   return error;
386 }
387
388 VLIB_CLI_COMMAND (cmd_show_frame_queue,static) = {
389     .path = "show frame-queue",
390     .short_help = "show frame-queue trace",
391     .function = show_frame_queue,
392 };
393
394
395 /*
396  * Modify the number of elements on the frame_queues
397  */
398 static clib_error_t *
399 test_frame_queue_nelts (vlib_main_t *vm, unformat_input_t *input,
400                         vlib_cli_command_t *cmd)
401 {
402   clib_error_t * error = NULL;
403   u32 num_fq;
404   u32 fqix;
405   u32 nelts = 0;
406
407   unformat(input, "%d", &nelts);
408   if ((nelts != 4) && (nelts != 8) && (nelts != 16) && (nelts != 32)) {
409       return clib_error_return(0, "expecting 4,8,16,32");
410   }
411
412   num_fq = vec_len(vlib_frame_queues);
413   if (num_fq == 0)
414     {
415       vlib_cli_output(vm, "No frame queues exist\n");
416       return error;
417     }
418
419   for (fqix=0; fqix<num_fq; fqix++) {
420     vlib_frame_queues[fqix]->nelts = nelts;
421   } 
422
423   return error;
424 }
425
426 VLIB_CLI_COMMAND (cmd_test_frame_queue_nelts,static) = {
427     .path = "test frame-queue nelts",
428     .short_help = "test frame-queue nelts (4,8,16,32)",
429     .function = test_frame_queue_nelts,
430 };
431
432
433 /*
434  * Modify the max number of packets pulled off the frame queues
435  */
436 static clib_error_t *
437 test_frame_queue_threshold (vlib_main_t *vm, unformat_input_t *input,
438                             vlib_cli_command_t *cmd)
439 {
440   clib_error_t * error = NULL;
441   u32 num_fq;
442   u32 fqix;
443   u32 threshold = 0;
444
445   if (unformat(input, "%d", &threshold)) {
446   } else {
447       vlib_cli_output(vm, "expecting threshold value\n");
448       return error;
449   }
450
451   if (threshold == 0)
452     threshold = ~0;
453
454   num_fq = vec_len(vlib_frame_queues);
455   if (num_fq == 0)
456     {
457       vlib_cli_output(vm, "No frame queues exist\n");
458       return error;
459     }
460
461   for (fqix=0; fqix<num_fq; fqix++) {
462     vlib_frame_queues[fqix]->vector_threshold = threshold;
463   } 
464
465   return error;
466 }
467
468 VLIB_CLI_COMMAND (cmd_test_frame_queue_threshold,static) = {
469     .path = "test frame-queue threshold",
470     .short_help = "test frame-queue threshold N (0=no limit)",
471     .function = test_frame_queue_threshold,
472 };
473
474 static void
475 show_efd_config (vlib_main_t * vm)
476 {
477     vlib_thread_main_t * tm = vlib_get_thread_main();
478     dpdk_main_t * dm = &dpdk_main;
479
480     vlib_cli_output(vm,
481                     "dpdk:   (0x%04x) enabled:%d monitor:%d drop_all:%d\n"
482                     "  dpdk_queue_hi_thresh          %d\n"
483                     "  consec_full_frames_hi_thresh  %d\n"
484                     "---------\n"
485                     "worker: (0x%04x) enabled:%d monitor:%d\n"
486                     "  worker_queue_hi_thresh        %d\n",
487                     dm->efd.enabled,
488                     ((dm->efd.enabled & DPDK_EFD_DISCARD_ENABLED) ? 1:0),
489                     ((dm->efd.enabled & DPDK_EFD_MONITOR_ENABLED) ? 1:0),
490                     ((dm->efd.enabled & DPDK_EFD_DROPALL_ENABLED) ? 1:0),
491                     dm->efd.queue_hi_thresh,
492                     dm->efd.consec_full_frames_hi_thresh,
493                     tm->efd.enabled,
494                     ((tm->efd.enabled & VLIB_EFD_DISCARD_ENABLED) ? 1:0),
495                     ((dm->efd.enabled & VLIB_EFD_MONITOR_ENABLED) ? 1:0),
496                     tm->efd.queue_hi_thresh);
497     vlib_cli_output(vm,
498                     "---------\n"
499                     "ip_prec_bitmap   0x%02x\n"
500                     "mpls_exp_bitmap  0x%02x\n"
501                     "vlan_cos_bitmap  0x%02x\n",
502                     tm->efd.ip_prec_bitmap,
503                     tm->efd.mpls_exp_bitmap,
504                     tm->efd.vlan_cos_bitmap);
505 }
506
507 static clib_error_t *
508 show_efd (vlib_main_t * vm,
509           unformat_input_t * input,
510           vlib_cli_command_t * cmd)
511 {
512
513     if (unformat(input, "config")) {
514         show_efd_config(vm);
515     } else if (unformat(input, "dpdk")) {
516         dpdk_main_t * dm = &dpdk_main;
517         dpdk_device_t * xd;
518         u32 device_id = ~0;
519
520         unformat(input, "device %d", &device_id);
521         vec_foreach (xd, dm->devices) {
522             if ((xd->device_index == device_id) || (device_id == ~0)) {
523                 show_dpdk_device_stats(vm, xd);
524             }
525         }
526     } else if (unformat(input, "worker")) {
527         vlib_thread_main_t * tm = vlib_get_thread_main();
528         vlib_frame_queue_t *fq;
529         vlib_thread_registration_t * tr;
530         int thread_id;
531         u32 num_workers = 0;
532         u32 first_worker_index = 0;
533         uword * p;
534
535         p = hash_get_mem (tm->thread_registrations_by_name, "workers");
536         ASSERT (p);
537         tr = (vlib_thread_registration_t *) p[0];
538         if (tr)
539           {
540             num_workers = tr->count;
541             first_worker_index = tr->first_index;
542           }
543
544         vlib_cli_output(vm,
545                         "num_workers               %d\n"
546                         "first_worker_index        %d\n"
547                         "vlib_frame_queues[%d]:\n",
548                         num_workers,
549                         first_worker_index,
550                         tm->n_vlib_mains);
551
552         for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) {
553             fq = vlib_frame_queues[thread_id];
554             if (fq) {
555                 vlib_cli_output(vm,
556                                 "%2d: frames_queued         %u\n"
557                                 "    frames_queued_hint    %u\n"
558                                 "    enqueue_full_events   %u\n"
559                                 "    enqueue_efd_discards  %u\n",
560                                 thread_id,
561                                 (fq->tail - fq->head),
562                                 (fq->tail - fq->head_hint),
563                                 fq->enqueue_full_events,
564                                 fq->enqueue_efd_discards);
565             }
566         }
567     } else if (unformat(input, "help")) {
568         vlib_cli_output(vm, "Usage: show efd config | "
569                         "dpdk [device <id>] | worker\n");
570     } else {
571         show_efd_config(vm);
572     }
573
574     return 0;
575 }
576
577 VLIB_CLI_COMMAND (show_efd_command, static) = {
578   .path = "show efd",
579   .short_help = "Show efd [device <id>] | [config]",
580   .function = show_efd,
581 };
582
583 static clib_error_t *
584 clear_efd (vlib_main_t * vm,
585            unformat_input_t * input,
586            vlib_cli_command_t * cmd)
587 {
588     dpdk_main_t * dm = &dpdk_main;
589     dpdk_device_t * xd;
590     vlib_thread_main_t * tm = vlib_get_thread_main();
591     vlib_frame_queue_t *fq;
592     int thread_id;
593
594     vec_foreach (xd, dm->devices) {
595         xd->efd_agent.last_burst_sz = 0;
596         xd->efd_agent.max_burst_sz = 0;
597         xd->efd_agent.full_frames_cnt = 0;
598         xd->efd_agent.consec_full_frames_cnt = 0;
599         xd->efd_agent.congestion_cnt = 0;
600         xd->efd_agent.last_poll_time = 0;
601         xd->efd_agent.max_poll_delay = 0;
602         xd->efd_agent.discard_cnt = 0;
603         xd->efd_agent.total_packet_cnt = 0;
604     }
605
606     for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) {
607         fq = vlib_frame_queues[thread_id];
608         if (fq) {
609             fq->enqueue_full_events = 0;
610             fq->enqueue_efd_discards = 0;
611         }
612     }
613
614     return 0;
615 }
616
617 VLIB_CLI_COMMAND (clear_efd_command,static) = {
618   .path = "clear efd",
619   .short_help = "Clear early-fast-discard counters",
620   .function = clear_efd,
621 };
622
623 static clib_error_t *
624 parse_op_and_prec (vlib_main_t *vm, unformat_input_t *input,
625                    vlib_cli_command_t *cmd,
626                    char *prec_type, u8 *prec_bitmap)
627 {
628     clib_error_t * error = NULL;
629     u8 op = 0;
630     u8 prec = 0;
631
632     if (unformat(input, "ge")) {
633         op = EFD_OPERATION_GREATER_OR_EQUAL;
634     } else if (unformat(input, "lt")) {
635         op = EFD_OPERATION_LESS_THAN;
636     } else if (unformat(input, "help")) {
637         vlib_cli_output(vm,
638             "enter operation [ge | lt] and precedence <0-7>)");
639         return (error);
640     } else {
641         return clib_error_return(0, "unknown input `%U'",
642                                   format_unformat_error, input);
643     }
644
645     if (unformat (input, "%u", &prec)) {
646          if (prec > 7) {
647              return clib_error_return(0, "precedence %d is out of range <0-7>",
648                                       prec);
649          }
650     } else {
651         return clib_error_return(0, "unknown input `%U'",
652                                  format_unformat_error, input);
653     }
654
655     set_efd_bitmap(prec_bitmap, prec, op);
656
657     vlib_cli_output(vm,
658         "EFD will be set for %s precedence %s%u%s.",
659         prec_type,
660         (op == EFD_OPERATION_LESS_THAN) ? "less than " : "",
661         prec,
662         (op == EFD_OPERATION_GREATER_OR_EQUAL) ? " and greater" : "");
663
664     return (error);
665 }
666
667
668 static clib_error_t *
669 set_efd (vlib_main_t *vm, unformat_input_t *input,
670           vlib_cli_command_t *cmd)
671 {
672     dpdk_main_t * dm = &dpdk_main;
673     vlib_thread_main_t * tm = vlib_get_thread_main();
674     clib_error_t * error = NULL;
675
676     if (unformat(input, "enable")) {
677         if (unformat(input, "dpdk")) {
678             dm->efd.enabled |= DPDK_EFD_DISCARD_ENABLED;
679         } else if (unformat(input, "worker")) {
680             tm->efd.enabled |= VLIB_EFD_DISCARD_ENABLED;
681         } else if (unformat(input, "monitor")) {
682             dm->efd.enabled |= DPDK_EFD_MONITOR_ENABLED;
683             tm->efd.enabled |= VLIB_EFD_MONITOR_ENABLED;
684         } else if (unformat(input, "drop_all")) {
685             dm->efd.enabled |= DPDK_EFD_DROPALL_ENABLED;
686         } else if (unformat(input, "default")) {
687             dm->efd.enabled = (DPDK_EFD_DISCARD_ENABLED |
688                                DPDK_EFD_MONITOR_ENABLED);
689             tm->efd.enabled = (VLIB_EFD_DISCARD_ENABLED |
690                                VLIB_EFD_MONITOR_ENABLED);
691         } else {
692             return clib_error_return(0, "Usage: set efd enable [dpdk | "
693                                      "worker | monitor | drop_all | default]");
694         }
695     } else if (unformat(input, "disable")) {
696         if (unformat(input, "dpdk")) {
697             dm->efd.enabled &= ~DPDK_EFD_DISCARD_ENABLED;
698         } else if (unformat(input, "worker")) {
699             tm->efd.enabled &= ~VLIB_EFD_DISCARD_ENABLED;
700         } else if (unformat(input, "monitor")) {
701             dm->efd.enabled &= ~DPDK_EFD_MONITOR_ENABLED;
702             tm->efd.enabled &= ~VLIB_EFD_MONITOR_ENABLED;
703         } else if (unformat(input, "drop_all")) {
704             dm->efd.enabled &= ~DPDK_EFD_DROPALL_ENABLED;
705         } else  if (unformat(input, "all")) {
706             dm->efd.enabled = 0;
707             tm->efd.enabled = 0;
708         } else {
709             return clib_error_return(0, "Usage: set efd disable [dpdk | "
710                                      "worker | monitor | drop_all | all]");
711         }
712     } else if (unformat(input, "worker_queue_hi_thresh")) {
713         u32 mark;
714         if (unformat (input, "%u", &mark)) {
715             tm->efd.queue_hi_thresh = mark;
716         } else {
717             return clib_error_return(0, "unknown input `%U'",
718                                      format_unformat_error, input);
719         }
720     } else if (unformat(input, "dpdk_device_hi_thresh")) {
721         u32 thresh;
722         if (unformat (input, "%u", &thresh)) {
723             dm->efd.queue_hi_thresh = thresh;
724         } else {
725             return clib_error_return(0, "unknown input `%U'",
726                                      format_unformat_error, input);
727         }
728     } else if (unformat(input, "consec_full_frames_hi_thresh")) {
729         u32 thresh;
730         if (unformat (input, "%u", &thresh)) {
731             dm->efd.consec_full_frames_hi_thresh = thresh;
732         } else {
733             return clib_error_return(0, "unknown input `%U'",
734                                      format_unformat_error, input);
735         }
736     } else if (unformat(input, "ip-prec")) {
737         return (parse_op_and_prec(vm, input, cmd,
738                                  "ip", &tm->efd.ip_prec_bitmap));
739     } else if (unformat(input, "mpls-exp")) {
740         return (parse_op_and_prec(vm, input, cmd,
741                                  "mpls", &tm->efd.mpls_exp_bitmap));
742     } else if (unformat(input, "vlan-cos")) {
743         return (parse_op_and_prec(vm, input, cmd,
744                                  "vlan", &tm->efd.vlan_cos_bitmap));
745     } else if (unformat(input, "help")) {
746         vlib_cli_output(vm,
747             "Usage:\n"
748             "  set efd enable <dpdk | worker | monitor | drop_all | default> |\n"
749             "  set efd disable <dpdk | worker | monitor | drop_all | all> |\n"
750             "  set efd <ip-prec | mpls-exp | vlan-cos> <ge | lt> <0-7>\n"
751             "  set efd worker_queue_hi_thresh <0-32> |\n"
752             "  set efd dpdk_device_hi_thresh <0-%d> |\n"
753             "  set efd consec_full_frames_hi_thresh <count> |\n",
754             DPDK_NB_RX_DESC_10GE);
755     } else {
756         return clib_error_return(0, "unknown input `%U'",
757                                   format_unformat_error, input);
758     }
759
760     return error;
761 }
762
763 VLIB_CLI_COMMAND (cmd_set_efd,static) = {
764     .path = "set efd",
765     .short_help = "set early-fast-discard commands",
766     .function = set_efd,
767 };
768
769 static clib_error_t *
770 set_dpdk_if_desc (vlib_main_t *vm, unformat_input_t *input,
771           vlib_cli_command_t *cmd)
772 {
773   unformat_input_t _line_input, * line_input = &_line_input;
774   dpdk_main_t * dm = &dpdk_main;
775   vnet_hw_interface_t * hw;
776   dpdk_device_t * xd;
777   u32 hw_if_index = (u32) ~0;
778   u32 nb_rx_desc = (u32) ~0;
779   u32 nb_tx_desc = (u32) ~0;
780   clib_error_t * rv;
781
782   if (! unformat_user (input, unformat_line_input, line_input))
783     return 0;
784
785   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
786     if (unformat (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
787                   &hw_if_index))
788       ;
789     else if (unformat (line_input, "tx %d", &nb_tx_desc))
790       ;
791     else if (unformat (line_input, "rx %d", &nb_rx_desc))
792       ;
793     else
794       return clib_error_return (0, "parse error: '%U'",
795                                 format_unformat_error, line_input);
796   }
797
798   unformat_free (line_input);
799
800   if (hw_if_index == (u32) ~0)
801     return clib_error_return (0, "please specify valid interface name");
802
803   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
804   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
805
806   if (xd->dev_type != VNET_DPDK_DEV_ETH)
807     return clib_error_return (0, "number of descriptors can be set only for "
808                               "physical devices");
809
810   if ((nb_rx_desc == (u32) ~0 || nb_rx_desc == xd->nb_rx_desc) &&
811       (nb_tx_desc == (u32) ~0 || nb_tx_desc == xd->nb_tx_desc))
812     return clib_error_return (0, "nothing changed");
813
814   if (nb_rx_desc != (u32) ~0)
815         xd->nb_rx_desc = nb_rx_desc;
816
817   if (nb_tx_desc != (u32) ~0)
818         xd->nb_rx_desc = nb_rx_desc;
819
820   rv = dpdk_port_setup(dm, xd);
821
822   return rv < 0 ? rv : 0;
823 }
824
825 VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = {
826     .path = "set dpdk interface descriptors",
827     .short_help = "set dpdk interface descriptors <if-name> [rx <n>] [tx <n>]",
828     .function = set_dpdk_if_desc,
829 };
830
831 static clib_error_t *
832 show_dpdk_if_placement (vlib_main_t *vm, unformat_input_t *input,
833           vlib_cli_command_t *cmd)
834 {
835   vlib_thread_main_t * tm = vlib_get_thread_main();
836   dpdk_main_t * dm = &dpdk_main;
837   dpdk_device_and_queue_t * dq;
838   int cpu;
839
840   if (tm->n_vlib_mains == 1)
841     vlib_cli_output(vm, "All interfaces are handled by main thread");
842
843   for(cpu = 0; cpu < vec_len(dm->devices_by_cpu); cpu++)
844     {
845       if (vec_len(dm->devices_by_cpu[cpu]))
846         vlib_cli_output(vm, "Thread %u (%s at lcore %u):", cpu,
847                         vlib_worker_threads[cpu].name,
848                         vlib_worker_threads[cpu].dpdk_lcore_id);
849
850       vec_foreach(dq, dm->devices_by_cpu[cpu])
851         {
852           u32 hw_if_index = dm->devices[dq->device].vlib_hw_if_index;
853           vnet_hw_interface_t * hi =  vnet_get_hw_interface(dm->vnet_main, hw_if_index);
854           vlib_cli_output(vm, "  %v queue %u", hi->name, dq->queue_id);
855         }
856     }
857   return 0;
858 }
859
860 VLIB_CLI_COMMAND (cmd_show_dpdk_if_placement,static) = {
861     .path = "show dpdk interface placement",
862     .short_help = "show dpdk interface placement",
863     .function = show_dpdk_if_placement,
864 };
865
866 static int
867 dpdk_device_queue_sort(void * a1, void * a2)
868 {
869   dpdk_device_and_queue_t * dq1 = a1;
870   dpdk_device_and_queue_t * dq2 = a2;
871
872   if (dq1->device > dq2->device)
873     return 1;
874   else if (dq1->device < dq2->device)
875     return -1;
876   else if (dq1->queue_id > dq2->queue_id)
877     return 1;
878   else if (dq1->queue_id < dq2->queue_id)
879     return -1;
880   else
881     return 0;
882 }
883
884 static clib_error_t *
885 set_dpdk_if_placement (vlib_main_t *vm, unformat_input_t *input,
886           vlib_cli_command_t *cmd)
887 {
888   unformat_input_t _line_input, * line_input = &_line_input;
889   dpdk_main_t * dm = &dpdk_main;
890   dpdk_device_and_queue_t * dq;
891   vnet_hw_interface_t * hw;
892   dpdk_device_t * xd;
893   u32 hw_if_index = (u32) ~0;
894   u32 queue = (u32) 0;
895   u32 cpu = (u32) ~0;
896   int i;
897
898   if (! unformat_user (input, unformat_line_input, line_input))
899     return 0;
900
901   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
902     if (unformat (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
903                   &hw_if_index))
904       ;
905     else if (unformat (line_input, "queue %d", &queue))
906       ;
907     else if (unformat (line_input, "thread %d", &cpu))
908       ;
909     else
910       return clib_error_return (0, "parse error: '%U'",
911                                 format_unformat_error, line_input);
912   }
913
914   unformat_free (line_input);
915
916   if (hw_if_index == (u32) ~0)
917     return clib_error_return (0, "please specify valid interface name");
918
919   if (cpu < dm->input_cpu_first_index ||
920       cpu >= (dm->input_cpu_first_index + dm->input_cpu_count))
921     return clib_error_return (0, "please specify valid thread id");
922
923   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
924   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
925
926   for(i = 0; i < vec_len(dm->devices_by_cpu); i++)
927     {
928       vec_foreach(dq, dm->devices_by_cpu[i])
929         {
930           if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index &&
931               queue == dq->queue_id)
932             {
933               if (cpu == i) /* nothing to do */
934                 return 0;
935
936               vec_del1(dm->devices_by_cpu[i], dq - dm->devices_by_cpu[i]);
937               vec_add2(dm->devices_by_cpu[cpu], dq, 1);
938               dq->queue_id = queue;
939               dq->device = xd->device_index;
940               xd->cpu_socket_id_by_queue[queue] =
941                 rte_lcore_to_socket_id(vlib_worker_threads[cpu].dpdk_lcore_id);
942
943               vec_sort_with_function(dm->devices_by_cpu[i],
944                                      dpdk_device_queue_sort);
945
946               vec_sort_with_function(dm->devices_by_cpu[cpu],
947                                      dpdk_device_queue_sort);
948
949               if (vec_len(dm->devices_by_cpu[i]) == 0)
950                 vlib_node_set_state (vlib_mains[i], dpdk_input_node.index,
951                                      VLIB_NODE_STATE_DISABLED);
952
953               if (vec_len(dm->devices_by_cpu[cpu]) == 1)
954                 vlib_node_set_state (vlib_mains[cpu], dpdk_input_node.index,
955                                      VLIB_NODE_STATE_POLLING);
956
957               return 0;
958             }
959         }
960     }
961
962   return clib_error_return (0, "not found");
963 }
964
965 VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = {
966     .path = "set dpdk interface placement",
967     .short_help = "set dpdk interface placement <if-name> [queue <n>]  thread <n>",
968     .function = set_dpdk_if_placement,
969 };
970
971 clib_error_t *
972 dpdk_cli_init (vlib_main_t * vm)
973 {
974   return 0;
975 }
976
977 VLIB_INIT_FUNCTION (dpdk_cli_init);