Initial commit of vpp code.
[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 };
192
193 static clib_error_t *
194 test_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
195                  vlib_cli_command_t * cmd)
196 {
197   static u32 * allocated_buffers;
198   u32 n_alloc = 0;
199   u32 n_free = 0;
200   u32 first, actual_alloc;
201
202   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
203     {
204       if (unformat (input, "allocate %d", &n_alloc))
205         ;
206       else if (unformat (input, "free %d", &n_free))
207         ;
208       else
209         break;
210     }
211
212   if (n_free)
213     {
214       if (vec_len (allocated_buffers) < n_free)
215         return clib_error_return (0, "Can't free %d, only %d allocated",
216                                   n_free, vec_len (allocated_buffers));
217
218       first = vec_len(allocated_buffers) - n_free;
219       vlib_buffer_free (vm, allocated_buffers + first, n_free);
220       _vec_len (allocated_buffers) = first;
221     }
222   if (n_alloc)
223     {
224       first = vec_len (allocated_buffers);
225       vec_validate (allocated_buffers,
226                     vec_len (allocated_buffers) + n_alloc - 1);
227
228       actual_alloc = vlib_buffer_alloc (vm, allocated_buffers + first,
229                                         n_alloc);
230       _vec_len (allocated_buffers) = first + actual_alloc;
231
232       if (actual_alloc < n_alloc)
233         vlib_cli_output (vm, "WARNING: only allocated %d buffers",
234                          actual_alloc);
235     }
236
237   vlib_cli_output (vm, "Currently %d buffers allocated",
238                    vec_len (allocated_buffers));
239
240   if (allocated_buffers && vec_len(allocated_buffers) == 0)
241     vec_free(allocated_buffers);
242
243   return 0;
244 }
245
246 VLIB_CLI_COMMAND (cmd_test_dpdk_bufferr,static) = {
247     .path = "test dpdk buffer",
248     .short_help = "test dpdk buffer [allocate <nn>][free <nn>]",
249     .function = test_dpdk_buffer,
250 };
251
252 static void
253 show_dpdk_device_stats (vlib_main_t * vm, dpdk_device_t * xd)
254 {
255     vlib_cli_output(vm,
256                     "device_index %d\n"
257                     "  last_burst_sz           %d\n"
258                     "  max_burst_sz            %d\n"
259                     "  full_frames_cnt         %u\n"
260                     "  consec_full_frames_cnt  %u\n"
261                     "  congestion_cnt          %d\n"
262                     "  last_poll_time          %llu\n"
263                     "  max_poll_delay          %llu\n"
264                     "  discard_cnt             %u\n"
265                     "  total_packet_cnt        %u\n",
266                     xd->device_index,
267                     xd->efd_agent.last_burst_sz,
268                     xd->efd_agent.max_burst_sz,
269                     xd->efd_agent.full_frames_cnt,
270                     xd->efd_agent.consec_full_frames_cnt,
271                     xd->efd_agent.congestion_cnt,
272                     xd->efd_agent.last_poll_time,
273                     xd->efd_agent.max_poll_delay,
274                     xd->efd_agent.discard_cnt,
275                     xd->efd_agent.total_packet_cnt);
276
277     u32 device_queue_sz = rte_eth_rx_queue_count(xd->device_index,
278                                                  0 /* queue_id */);
279     vlib_cli_output(vm,
280                     "  device_queue_sz         %u\n",
281                     device_queue_sz);
282 }
283
284
285 /*
286  * Trigger threads to grab frame queue trace data
287  */
288 static clib_error_t *
289 trace_frame_queue (vlib_main_t *vm, unformat_input_t *input,
290                   vlib_cli_command_t *cmd)
291 {
292   clib_error_t * error = NULL;
293   frame_queue_trace_t *fqt;
294   u32 num_fq;
295   u32 fqix;
296   u32 enable = 0;
297
298   if (unformat(input, "on")) {
299     enable = 1;
300   } else if (unformat(input, "off")) {
301     enable = 0;
302   } else {
303       return clib_error_return(0, "expecting on or off");
304   }
305
306   num_fq = vec_len(vlib_frame_queues);
307   if (num_fq == 0)
308     {
309       vlib_cli_output(vm, "No frame queues exist\n");
310       return error;
311     }
312
313   // Allocate storage for trace if necessary
314   vec_validate_aligned(frame_queue_traces, num_fq-1, CLIB_CACHE_LINE_BYTES);
315
316   for (fqix=0; fqix<num_fq; fqix++) {
317     fqt = &frame_queue_traces[fqix];
318
319     memset(fqt->n_vectors, 0xff, sizeof(fqt->n_vectors));
320     fqt->written = 0;
321     vlib_frame_queues[fqix]->trace = enable;
322   }
323   return error;
324 }
325
326 VLIB_CLI_COMMAND (cmd_trace_frame_queue,static) = {
327     .path = "trace frame-queue",
328     .short_help = "trace frame-queue (on|off)",
329     .function = trace_frame_queue,
330 };
331
332
333 /*
334  * Display frame queue trace data gathered by threads.
335  */
336 static clib_error_t *
337 show_frame_queue (vlib_main_t *vm, unformat_input_t *input,
338                   vlib_cli_command_t *cmd)
339 {
340   clib_error_t * error = NULL;
341   frame_queue_trace_t *fqt;
342   u32 num_fq;
343   u32 fqix;
344
345   num_fq = vec_len(frame_queue_traces);
346   if (num_fq == 0)
347     {
348       vlib_cli_output(vm, "No trace data for frame queues\n");
349       return error;
350     }
351
352   for (fqix=0; fqix<num_fq; fqix++) {
353     fqt = &frame_queue_traces[fqix];
354
355     vlib_cli_output(vm, "Thread %d %v\n", fqix, vlib_worker_threads[fqix].name);
356
357     if (fqt->written == 0)
358       {
359         vlib_cli_output(vm, "  no trace data\n");
360         continue;
361       }
362
363     vlib_cli_output(vm, "  vector-threshold %d  ring size %d  in use %d\n",
364                     fqt->threshold, fqt->nelts, fqt->n_in_use);
365     vlib_cli_output(vm, "  head %12d  head_hint %12d  tail %12d\n",
366                     fqt->head, fqt->head_hint, fqt->tail);
367     vlib_cli_output(vm, "  %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
368                     fqt->n_vectors[0], fqt->n_vectors[1], fqt->n_vectors[2], fqt->n_vectors[3],
369                     fqt->n_vectors[4], fqt->n_vectors[5], fqt->n_vectors[6], fqt->n_vectors[7],
370                     fqt->n_vectors[8], fqt->n_vectors[9], fqt->n_vectors[10], fqt->n_vectors[11],
371                     fqt->n_vectors[12], fqt->n_vectors[13], fqt->n_vectors[14], fqt->n_vectors[15]);
372
373     if (fqt->nelts > 16)
374       {
375         vlib_cli_output(vm, "  %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
376                         fqt->n_vectors[16], fqt->n_vectors[17], fqt->n_vectors[18], fqt->n_vectors[19],
377                         fqt->n_vectors[20], fqt->n_vectors[21], fqt->n_vectors[22], fqt->n_vectors[23],
378                         fqt->n_vectors[24], fqt->n_vectors[25], fqt->n_vectors[26], fqt->n_vectors[27],
379                         fqt->n_vectors[28], fqt->n_vectors[29], fqt->n_vectors[30], fqt->n_vectors[31]);
380       }
381   }
382   return error;
383 }
384
385 VLIB_CLI_COMMAND (cmd_show_frame_queue,static) = {
386     .path = "show frame-queue",
387     .short_help = "show frame-queue trace",
388     .function = show_frame_queue,
389 };
390
391
392 /*
393  * Modify the number of elements on the frame_queues
394  */
395 static clib_error_t *
396 test_frame_queue_nelts (vlib_main_t *vm, unformat_input_t *input,
397                         vlib_cli_command_t *cmd)
398 {
399   clib_error_t * error = NULL;
400   u32 num_fq;
401   u32 fqix;
402   u32 nelts = 0;
403
404   unformat(input, "%d", &nelts);
405   if ((nelts != 4) && (nelts != 8) && (nelts != 16) && (nelts != 32)) {
406       return clib_error_return(0, "expecting 4,8,16,32");
407   }
408
409   num_fq = vec_len(vlib_frame_queues);
410   if (num_fq == 0)
411     {
412       vlib_cli_output(vm, "No frame queues exist\n");
413       return error;
414     }
415
416   for (fqix=0; fqix<num_fq; fqix++) {
417     vlib_frame_queues[fqix]->nelts = nelts;
418   } 
419
420   return error;
421 }
422
423 VLIB_CLI_COMMAND (cmd_test_frame_queue_nelts,static) = {
424     .path = "test frame-queue nelts",
425     .short_help = "test frame-queue nelts (4,8,16,32)",
426     .function = test_frame_queue_nelts,
427 };
428
429
430 /*
431  * Modify the max number of packets pulled off the frame queues
432  */
433 static clib_error_t *
434 test_frame_queue_threshold (vlib_main_t *vm, unformat_input_t *input,
435                             vlib_cli_command_t *cmd)
436 {
437   clib_error_t * error = NULL;
438   u32 num_fq;
439   u32 fqix;
440   u32 threshold = 0;
441
442   if (unformat(input, "%d", &threshold)) {
443   } else {
444       vlib_cli_output(vm, "expecting threshold value\n");
445       return error;
446   }
447
448   if (threshold == 0)
449     threshold = ~0;
450
451   num_fq = vec_len(vlib_frame_queues);
452   if (num_fq == 0)
453     {
454       vlib_cli_output(vm, "No frame queues exist\n");
455       return error;
456     }
457
458   for (fqix=0; fqix<num_fq; fqix++) {
459     vlib_frame_queues[fqix]->vector_threshold = threshold;
460   } 
461
462   return error;
463 }
464
465 VLIB_CLI_COMMAND (cmd_test_frame_queue_threshold,static) = {
466     .path = "test frame-queue threshold",
467     .short_help = "test frame-queue threshold N (0=no limit)",
468     .function = test_frame_queue_threshold,
469 };
470
471 static void
472 show_efd_config (vlib_main_t * vm)
473 {
474     vlib_thread_main_t * tm = vlib_get_thread_main();
475     dpdk_main_t * dm = &dpdk_main;
476
477     vlib_cli_output(vm,
478                     "dpdk:   (0x%04x) enabled:%d monitor:%d drop_all:%d\n"
479                     "  dpdk_queue_hi_thresh          %d\n"
480                     "  consec_full_frames_hi_thresh  %d\n"
481                     "---------\n"
482                     "worker: (0x%04x) enabled:%d monitor:%d\n"
483                     "  worker_queue_hi_thresh        %d\n",
484                     dm->efd.enabled,
485                     ((dm->efd.enabled & DPDK_EFD_DISCARD_ENABLED) ? 1:0),
486                     ((dm->efd.enabled & DPDK_EFD_MONITOR_ENABLED) ? 1:0),
487                     ((dm->efd.enabled & DPDK_EFD_DROPALL_ENABLED) ? 1:0),
488                     dm->efd.queue_hi_thresh,
489                     dm->efd.consec_full_frames_hi_thresh,
490                     tm->efd.enabled,
491                     ((tm->efd.enabled & VLIB_EFD_DISCARD_ENABLED) ? 1:0),
492                     ((dm->efd.enabled & VLIB_EFD_MONITOR_ENABLED) ? 1:0),
493                     tm->efd.queue_hi_thresh);
494     vlib_cli_output(vm,
495                     "---------\n"
496                     "ip_prec_bitmap   0x%02x\n"
497                     "mpls_exp_bitmap  0x%02x\n"
498                     "vlan_cos_bitmap  0x%02x\n",
499                     tm->efd.ip_prec_bitmap,
500                     tm->efd.mpls_exp_bitmap,
501                     tm->efd.vlan_cos_bitmap);
502 }
503
504 static clib_error_t *
505 show_efd (vlib_main_t * vm,
506           unformat_input_t * input,
507           vlib_cli_command_t * cmd)
508 {
509
510     if (unformat(input, "config")) {
511         show_efd_config(vm);
512     } else if (unformat(input, "dpdk")) {
513         dpdk_main_t * dm = &dpdk_main;
514         dpdk_device_t * xd;
515         u32 device_id = ~0;
516
517         unformat(input, "device %d", &device_id);
518         vec_foreach (xd, dm->devices) {
519             if ((xd->device_index == device_id) || (device_id == ~0)) {
520                 show_dpdk_device_stats(vm, xd);
521             }
522         }
523     } else if (unformat(input, "worker")) {
524         vlib_thread_main_t * tm = vlib_get_thread_main();
525         vlib_frame_queue_t *fq;
526         vlib_thread_registration_t * tr;
527         int thread_id;
528         u32 num_workers = 0;
529         u32 first_worker_index = 0;
530         uword * p;
531
532         p = hash_get_mem (tm->thread_registrations_by_name, "workers");
533         ASSERT (p);
534         tr = (vlib_thread_registration_t *) p[0];
535         if (tr)
536           {
537             num_workers = tr->count;
538             first_worker_index = tr->first_index;
539           }
540
541         vlib_cli_output(vm,
542                         "num_workers               %d\n"
543                         "first_worker_index        %d\n"
544                         "vlib_frame_queues[%d]:\n",
545                         num_workers,
546                         first_worker_index,
547                         tm->n_vlib_mains);
548
549         for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) {
550             fq = vlib_frame_queues[thread_id];
551             if (fq) {
552                 vlib_cli_output(vm,
553                                 "%2d: frames_queued         %u\n"
554                                 "    frames_queued_hint    %u\n"
555                                 "    enqueue_full_events   %u\n"
556                                 "    enqueue_efd_discards  %u\n",
557                                 thread_id,
558                                 (fq->tail - fq->head),
559                                 (fq->tail - fq->head_hint),
560                                 fq->enqueue_full_events,
561                                 fq->enqueue_efd_discards);
562             }
563         }
564     } else if (unformat(input, "help")) {
565         vlib_cli_output(vm, "Usage: show efd config | "
566                         "dpdk [device <id>] | worker\n");
567     } else {
568         show_efd_config(vm);
569     }
570
571     return 0;
572 }
573
574 VLIB_CLI_COMMAND (show_efd_command, static) = {
575   .path = "show efd",
576   .short_help = "Show efd [device <id>] | [config]",
577   .function = show_efd,
578 };
579
580 static clib_error_t *
581 clear_efd (vlib_main_t * vm,
582            unformat_input_t * input,
583            vlib_cli_command_t * cmd)
584 {
585     dpdk_main_t * dm = &dpdk_main;
586     dpdk_device_t * xd;
587     vlib_thread_main_t * tm = vlib_get_thread_main();
588     vlib_frame_queue_t *fq;
589     int thread_id;
590
591     vec_foreach (xd, dm->devices) {
592         xd->efd_agent.last_burst_sz = 0;
593         xd->efd_agent.max_burst_sz = 0;
594         xd->efd_agent.full_frames_cnt = 0;
595         xd->efd_agent.consec_full_frames_cnt = 0;
596         xd->efd_agent.congestion_cnt = 0;
597         xd->efd_agent.last_poll_time = 0;
598         xd->efd_agent.max_poll_delay = 0;
599         xd->efd_agent.discard_cnt = 0;
600         xd->efd_agent.total_packet_cnt = 0;
601     }
602
603     for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) {
604         fq = vlib_frame_queues[thread_id];
605         if (fq) {
606             fq->enqueue_full_events = 0;
607             fq->enqueue_efd_discards = 0;
608         }
609     }
610
611     return 0;
612 }
613
614 VLIB_CLI_COMMAND (clear_efd_command,static) = {
615   .path = "clear efd",
616   .short_help = "Clear early-fast-discard counters",
617   .function = clear_efd,
618 };
619
620 static clib_error_t *
621 parse_op_and_prec (vlib_main_t *vm, unformat_input_t *input,
622                    vlib_cli_command_t *cmd,
623                    char *prec_type, u8 *prec_bitmap)
624 {
625     clib_error_t * error = NULL;
626     u8 op = 0;
627     u8 prec = 0;
628
629     if (unformat(input, "ge")) {
630         op = EFD_OPERATION_GREATER_OR_EQUAL;
631     } else if (unformat(input, "lt")) {
632         op = EFD_OPERATION_LESS_THAN;
633     } else if (unformat(input, "help")) {
634         vlib_cli_output(vm,
635             "enter operation [ge | lt] and precedence <0-7>)");
636         return (error);
637     } else {
638         return clib_error_return(0, "unknown input `%U'",
639                                   format_unformat_error, input);
640     }
641
642     if (unformat (input, "%u", &prec)) {
643          if (prec > 7) {
644              return clib_error_return(0, "precedence %d is out of range <0-7>",
645                                       prec);
646          }
647     } else {
648         return clib_error_return(0, "unknown input `%U'",
649                                  format_unformat_error, input);
650     }
651
652     set_efd_bitmap(prec_bitmap, prec, op);
653
654     vlib_cli_output(vm,
655         "EFD will be set for %s precedence %s%u%s.",
656         prec_type,
657         (op == EFD_OPERATION_LESS_THAN) ? "less than " : "",
658         prec,
659         (op == EFD_OPERATION_GREATER_OR_EQUAL) ? " and greater" : "");
660
661     return (error);
662 }
663
664
665 static clib_error_t *
666 set_efd (vlib_main_t *vm, unformat_input_t *input,
667           vlib_cli_command_t *cmd)
668 {
669     dpdk_main_t * dm = &dpdk_main;
670     vlib_thread_main_t * tm = vlib_get_thread_main();
671     clib_error_t * error = NULL;
672
673     if (unformat(input, "enable")) {
674         if (unformat(input, "dpdk")) {
675             dm->efd.enabled |= DPDK_EFD_DISCARD_ENABLED;
676         } else if (unformat(input, "worker")) {
677             tm->efd.enabled |= VLIB_EFD_DISCARD_ENABLED;
678         } else if (unformat(input, "monitor")) {
679             dm->efd.enabled |= DPDK_EFD_MONITOR_ENABLED;
680             tm->efd.enabled |= VLIB_EFD_MONITOR_ENABLED;
681         } else if (unformat(input, "drop_all")) {
682             dm->efd.enabled |= DPDK_EFD_DROPALL_ENABLED;
683         } else if (unformat(input, "default")) {
684             dm->efd.enabled = (DPDK_EFD_DISCARD_ENABLED |
685                                DPDK_EFD_MONITOR_ENABLED);
686             tm->efd.enabled = (VLIB_EFD_DISCARD_ENABLED |
687                                VLIB_EFD_MONITOR_ENABLED);
688         } else {
689             return clib_error_return(0, "Usage: set efd enable [dpdk | "
690                                      "worker | monitor | drop_all | default]");
691         }
692     } else if (unformat(input, "disable")) {
693         if (unformat(input, "dpdk")) {
694             dm->efd.enabled &= ~DPDK_EFD_DISCARD_ENABLED;
695         } else if (unformat(input, "worker")) {
696             tm->efd.enabled &= ~VLIB_EFD_DISCARD_ENABLED;
697         } else if (unformat(input, "monitor")) {
698             dm->efd.enabled &= ~DPDK_EFD_MONITOR_ENABLED;
699             tm->efd.enabled &= ~VLIB_EFD_MONITOR_ENABLED;
700         } else if (unformat(input, "drop_all")) {
701             dm->efd.enabled &= ~DPDK_EFD_DROPALL_ENABLED;
702         } else  if (unformat(input, "all")) {
703             dm->efd.enabled = 0;
704             tm->efd.enabled = 0;
705         } else {
706             return clib_error_return(0, "Usage: set efd disable [dpdk | "
707                                      "worker | monitor | drop_all | all]");
708         }
709     } else if (unformat(input, "worker_queue_hi_thresh")) {
710         u32 mark;
711         if (unformat (input, "%u", &mark)) {
712             tm->efd.queue_hi_thresh = mark;
713         } else {
714             return clib_error_return(0, "unknown input `%U'",
715                                      format_unformat_error, input);
716         }
717     } else if (unformat(input, "dpdk_device_hi_thresh")) {
718         u32 thresh;
719         if (unformat (input, "%u", &thresh)) {
720             dm->efd.queue_hi_thresh = thresh;
721         } else {
722             return clib_error_return(0, "unknown input `%U'",
723                                      format_unformat_error, input);
724         }
725     } else if (unformat(input, "consec_full_frames_hi_thresh")) {
726         u32 thresh;
727         if (unformat (input, "%u", &thresh)) {
728             dm->efd.consec_full_frames_hi_thresh = thresh;
729         } else {
730             return clib_error_return(0, "unknown input `%U'",
731                                      format_unformat_error, input);
732         }
733     } else if (unformat(input, "ip-prec")) {
734         return (parse_op_and_prec(vm, input, cmd,
735                                  "ip", &tm->efd.ip_prec_bitmap));
736     } else if (unformat(input, "mpls-exp")) {
737         return (parse_op_and_prec(vm, input, cmd,
738                                  "mpls", &tm->efd.mpls_exp_bitmap));
739     } else if (unformat(input, "vlan-cos")) {
740         return (parse_op_and_prec(vm, input, cmd,
741                                  "vlan", &tm->efd.vlan_cos_bitmap));
742     } else if (unformat(input, "help")) {
743         vlib_cli_output(vm,
744             "Usage:\n"
745             "  set efd enable <dpdk | worker | monitor | drop_all | default> |\n"
746             "  set efd disable <dpdk | worker | monitor | drop_all | all> |\n"
747             "  set efd <ip-prec | mpls-exp | vlan-cos> <ge | lt> <0-7>\n"
748             "  set efd worker_queue_hi_thresh <0-32> |\n"
749             "  set efd dpdk_device_hi_thresh <0-%d> |\n"
750             "  set efd consec_full_frames_hi_thresh <count> |\n",
751             DPDK_NB_RX_DESC_10GE);
752     } else {
753         return clib_error_return(0, "unknown input `%U'",
754                                   format_unformat_error, input);
755     }
756
757     return error;
758 }
759
760 VLIB_CLI_COMMAND (cmd_set_efd,static) = {
761     .path = "set efd",
762     .short_help = "set early-fast-discard commands",
763     .function = set_efd,
764 };
765
766 static clib_error_t *
767 set_dpdk_if_desc (vlib_main_t *vm, unformat_input_t *input,
768           vlib_cli_command_t *cmd)
769 {
770   unformat_input_t _line_input, * line_input = &_line_input;
771   dpdk_main_t * dm = &dpdk_main;
772   vnet_hw_interface_t * hw;
773   dpdk_device_t * xd;
774   u32 hw_if_index = (u32) ~0;
775   u32 nb_rx_desc = (u32) ~0;
776   u32 nb_tx_desc = (u32) ~0;
777   clib_error_t * rv;
778
779   if (! unformat_user (input, unformat_line_input, line_input))
780     return 0;
781
782   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
783     if (unformat (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
784                   &hw_if_index))
785       ;
786     else if (unformat (line_input, "tx %d", &nb_tx_desc))
787       ;
788     else if (unformat (line_input, "rx %d", &nb_rx_desc))
789       ;
790     else
791       return clib_error_return (0, "parse error: '%U'",
792                                 format_unformat_error, line_input);
793   }
794
795   unformat_free (line_input);
796
797   if (hw_if_index == (u32) ~0)
798     return clib_error_return (0, "please specify valid interface name");
799
800   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
801   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
802
803   if (xd->dev_type != VNET_DPDK_DEV_ETH)
804     return clib_error_return (0, "number of descriptors can be set only for "
805                               "physical devices");
806
807   if ((nb_rx_desc == (u32) ~0 || nb_rx_desc == xd->nb_rx_desc) &&
808       (nb_tx_desc == (u32) ~0 || nb_tx_desc == xd->nb_tx_desc))
809     return clib_error_return (0, "nothing changed");
810
811   if (nb_rx_desc != (u32) ~0)
812         xd->nb_rx_desc = nb_rx_desc;
813
814   if (nb_tx_desc != (u32) ~0)
815         xd->nb_rx_desc = nb_rx_desc;
816
817   rv = dpdk_port_setup(dm, xd);
818
819   return rv < 0 ? rv : 0;
820 }
821
822 VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = {
823     .path = "set dpdk interface descriptors",
824     .short_help = "set dpdk interface descriptors <if-name> [rx <n>] [tx <n>]",
825     .function = set_dpdk_if_desc,
826 };
827
828 static clib_error_t *
829 show_dpdk_if_placement (vlib_main_t *vm, unformat_input_t *input,
830           vlib_cli_command_t *cmd)
831 {
832   vlib_thread_main_t * tm = vlib_get_thread_main();
833   dpdk_main_t * dm = &dpdk_main;
834   dpdk_device_and_queue_t * dq;
835   int cpu;
836
837   if (tm->n_vlib_mains == 1)
838     vlib_cli_output(vm, "All interfaces are handled by main thread");
839
840   for(cpu = 0; cpu < vec_len(dm->devices_by_cpu); cpu++)
841     {
842       if (vec_len(dm->devices_by_cpu[cpu]))
843         vlib_cli_output(vm, "Thread %u (%s at lcore %u):", cpu,
844                         vlib_worker_threads[cpu].name,
845                         vlib_worker_threads[cpu].dpdk_lcore_id);
846
847       vec_foreach(dq, dm->devices_by_cpu[cpu])
848         {
849           u32 hw_if_index = dm->devices[dq->device].vlib_hw_if_index;
850           vnet_hw_interface_t * hi =  vnet_get_hw_interface(dm->vnet_main, hw_if_index);
851           vlib_cli_output(vm, "  %v queue %u", hi->name, dq->queue_id);
852         }
853     }
854   return 0;
855 }
856
857 VLIB_CLI_COMMAND (cmd_show_dpdk_if_placement,static) = {
858     .path = "show dpdk interface placement",
859     .short_help = "show dpdk interface placement",
860     .function = show_dpdk_if_placement,
861 };
862
863 static int
864 dpdk_device_queue_sort(void * a1, void * a2)
865 {
866   dpdk_device_and_queue_t * dq1 = a1;
867   dpdk_device_and_queue_t * dq2 = a2;
868
869   if (dq1->device > dq2->device)
870     return 1;
871   else if (dq1->device < dq2->device)
872     return -1;
873   else if (dq1->queue_id > dq2->queue_id)
874     return 1;
875   else if (dq1->queue_id < dq2->queue_id)
876     return -1;
877   else
878     return 0;
879 }
880
881 static clib_error_t *
882 set_dpdk_if_placement (vlib_main_t *vm, unformat_input_t *input,
883           vlib_cli_command_t *cmd)
884 {
885   unformat_input_t _line_input, * line_input = &_line_input;
886   dpdk_main_t * dm = &dpdk_main;
887   dpdk_device_and_queue_t * dq;
888   vnet_hw_interface_t * hw;
889   dpdk_device_t * xd;
890   u32 hw_if_index = (u32) ~0;
891   u32 queue = (u32) 0;
892   u32 cpu = (u32) ~0;
893   int i;
894
895   if (! unformat_user (input, unformat_line_input, line_input))
896     return 0;
897
898   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
899     if (unformat (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
900                   &hw_if_index))
901       ;
902     else if (unformat (line_input, "queue %d", &queue))
903       ;
904     else if (unformat (line_input, "thread %d", &cpu))
905       ;
906     else
907       return clib_error_return (0, "parse error: '%U'",
908                                 format_unformat_error, line_input);
909   }
910
911   unformat_free (line_input);
912
913   if (hw_if_index == (u32) ~0)
914     return clib_error_return (0, "please specify valid interface name");
915
916   if (cpu < dm->input_cpu_first_index ||
917       cpu >= (dm->input_cpu_first_index + dm->input_cpu_count))
918     return clib_error_return (0, "please specify valid thread id");
919
920   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
921   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
922
923   for(i = 0; i < vec_len(dm->devices_by_cpu); i++)
924     {
925       vec_foreach(dq, dm->devices_by_cpu[i])
926         {
927           if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index &&
928               queue == dq->queue_id)
929             {
930               if (cpu == i) /* nothing to do */
931                 return 0;
932
933               vec_del1(dm->devices_by_cpu[i], dq - dm->devices_by_cpu[i]);
934               vec_add2(dm->devices_by_cpu[cpu], dq, 1);
935               dq->queue_id = queue;
936               dq->device = xd->device_index;
937               xd->cpu_socket_id_by_queue[queue] =
938                 rte_lcore_to_socket_id(vlib_worker_threads[cpu].dpdk_lcore_id);
939
940               vec_sort_with_function(dm->devices_by_cpu[i],
941                                      dpdk_device_queue_sort);
942
943               vec_sort_with_function(dm->devices_by_cpu[cpu],
944                                      dpdk_device_queue_sort);
945
946               if (vec_len(dm->devices_by_cpu[i]) == 0)
947                 vlib_node_set_state (vlib_mains[i], dpdk_input_node.index,
948                                      VLIB_NODE_STATE_DISABLED);
949
950               if (vec_len(dm->devices_by_cpu[cpu]) == 1)
951                 vlib_node_set_state (vlib_mains[cpu], dpdk_input_node.index,
952                                      VLIB_NODE_STATE_POLLING);
953
954               return 0;
955             }
956         }
957     }
958
959   return clib_error_return (0, "not found");
960 }
961
962 VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = {
963     .path = "set dpdk interface placement",
964     .short_help = "set dpdk interface placement <if-name> [queue <n>]  thread <n>",
965     .function = set_dpdk_if_placement,
966 };
967
968 clib_error_t *
969 dpdk_cli_init (vlib_main_t * vm)
970 {
971   return 0;
972 }
973
974 VLIB_INIT_FUNCTION (dpdk_cli_init);