bcc3d2f91a5bd16c973627ef785ed4d4e51eb816
[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 static clib_error_t *
29 pcap_trace_command_fn (vlib_main_t * vm,
30      unformat_input_t * input,
31      vlib_cli_command_t * cmd)
32 {
33   dpdk_main_t * dm = &dpdk_main;
34   u8 * filename;
35   u32 max;
36   int matched = 0;
37   clib_error_t * error = 0;
38
39   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
40     {
41       if (unformat (input, "on"))
42         {
43           if (dm->tx_pcap_enable == 0)
44             {
45               if (dm->pcap_filename == 0)
46                 dm->pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
47
48               memset (&dm->pcap_main, 0, sizeof (dm->pcap_main));
49               dm->pcap_main.file_name = (char *) dm->pcap_filename;
50               dm->pcap_main.n_packets_to_capture = 100;
51               if (dm->pcap_pkts_to_capture)
52                 dm->pcap_main.n_packets_to_capture = dm->pcap_pkts_to_capture;
53
54               dm->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
55               dm->tx_pcap_enable = 1;
56               matched = 1;
57               vlib_cli_output (vm, "pcap tx capture on...");
58             }
59           else
60             {
61               vlib_cli_output (vm, "pcap tx capture already on...");
62             }
63           matched = 1;
64         }
65       else if (unformat (input, "off"))
66         {
67           if (dm->tx_pcap_enable)
68             {
69               vlib_cli_output (vm, "captured %d pkts...",
70                                dm->pcap_main.n_packets_captured+1);
71               if (dm->pcap_main.n_packets_captured)
72                 {
73                   dm->pcap_main.n_packets_to_capture =
74                     dm->pcap_main.n_packets_captured;
75                   error = pcap_write (&dm->pcap_main);
76                   if (error)
77                     clib_error_report (error);
78                   else
79                     vlib_cli_output (vm, "saved to %s...", dm->pcap_filename);
80                 }
81             }
82           else
83             {
84               vlib_cli_output (vm, "pcap tx capture already off...");
85             }
86
87           dm->tx_pcap_enable = 0;
88           matched = 1;
89         }
90       else if (unformat (input, "max %d", &max))
91         {
92           dm->pcap_pkts_to_capture = max;
93           matched = 1;
94         }
95
96       else if (unformat (input, "intfc %U",
97                          unformat_vnet_sw_interface, dm->vnet_main,
98                          &dm->pcap_sw_if_index))
99         matched = 1;
100       else if (unformat (input, "intfc any"))
101         {
102           dm->pcap_sw_if_index = 0;
103           matched = 1;
104         }
105       else if (unformat (input, "file %s", &filename))
106         {
107           u8 * chroot_filename;
108           /* Brain-police user path input */
109           if (strstr((char *)filename, "..") || index((char *)filename, '/'))
110             {
111               vlib_cli_output (vm, "illegal characters in filename '%s'",
112                                filename);
113               continue;
114             }
115
116           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
117           vec_free (filename);
118
119           if (dm->pcap_filename)
120             vec_free (dm->pcap_filename);
121           vec_add1 (filename, 0);
122           dm->pcap_filename = chroot_filename;
123           matched = 1;
124         }
125       else if (unformat (input, "status"))
126         {
127           if (dm->tx_pcap_enable == 0)
128             {
129               vlib_cli_output (vm, "pcap tx capture is off...");
130               continue;
131             }
132
133           vlib_cli_output (vm, "pcap tx capture: %d of %d pkts...",
134                            dm->pcap_main.n_packets_captured,
135                            dm->pcap_main.n_packets_to_capture);
136           matched = 1;
137         }
138
139       else
140         break;
141     }
142
143   if (matched == 0)
144     return clib_error_return (0, "unknown input `%U'",
145                               format_unformat_error, input);
146
147   return 0;
148 }
149
150 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
151     .path = "pcap tx trace",
152     .short_help =
153     "pcap tx trace on off max <nn> intfc <intfc> file <name> status",
154     .function = pcap_trace_command_fn,
155 };
156
157
158 static clib_error_t *
159 show_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
160                  vlib_cli_command_t * cmd)
161 {
162   struct rte_mempool * rmp;
163   int i;
164
165   for(i = 0; i < vec_len(vm->buffer_main->pktmbuf_pools); i++)
166     {
167       rmp = vm->buffer_main->pktmbuf_pools[i];
168       if (rmp)
169         {
170           unsigned count = rte_mempool_count(rmp);
171           unsigned free_count = rte_mempool_free_count(rmp);
172
173           vlib_cli_output(vm, "name=\"%s\"  available = %7d allocated = %7d total = %7d\n",
174                           rmp->name, (u32)count, (u32)free_count,
175                           (u32)(count+free_count));
176         }
177       else
178         {
179            vlib_cli_output(vm, "rte_mempool is NULL (!)\n");
180         }
181     }
182   return 0;
183 }
184
185 VLIB_CLI_COMMAND (cmd_show_dpdk_bufferr,static) = {
186     .path = "show dpdk buffer",
187     .short_help = "show dpdk buffer state",
188     .function = show_dpdk_buffer,
189     .is_mp_safe = 1,
190 };
191
192 static clib_error_t *
193 test_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
194                  vlib_cli_command_t * cmd)
195 {
196   static u32 * allocated_buffers;
197   u32 n_alloc = 0;
198   u32 n_free = 0;
199   u32 first, actual_alloc;
200
201   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
202     {
203       if (unformat (input, "allocate %d", &n_alloc))
204         ;
205       else if (unformat (input, "free %d", &n_free))
206         ;
207       else
208         break;
209     }
210
211   if (n_free)
212     {
213       if (vec_len (allocated_buffers) < n_free)
214         return clib_error_return (0, "Can't free %d, only %d allocated",
215                                   n_free, vec_len (allocated_buffers));
216
217       first = vec_len(allocated_buffers) - n_free;
218       vlib_buffer_free (vm, allocated_buffers + first, n_free);
219       _vec_len (allocated_buffers) = first;
220     }
221   if (n_alloc)
222     {
223       first = vec_len (allocated_buffers);
224       vec_validate (allocated_buffers,
225                     vec_len (allocated_buffers) + n_alloc - 1);
226
227       actual_alloc = vlib_buffer_alloc (vm, allocated_buffers + first,
228                                         n_alloc);
229       _vec_len (allocated_buffers) = first + actual_alloc;
230
231       if (actual_alloc < n_alloc)
232         vlib_cli_output (vm, "WARNING: only allocated %d buffers",
233                          actual_alloc);
234     }
235
236   vlib_cli_output (vm, "Currently %d buffers allocated",
237                    vec_len (allocated_buffers));
238
239   if (allocated_buffers && vec_len(allocated_buffers) == 0)
240     vec_free(allocated_buffers);
241
242   return 0;
243 }
244
245 VLIB_CLI_COMMAND (cmd_test_dpdk_buffer,static) = {
246     .path = "test dpdk buffer",
247     .short_help = "test dpdk buffer [allocate <nn>][free <nn>]",
248     .function = test_dpdk_buffer,
249     .is_mp_safe = 1,
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 static void
285 show_efd_config (vlib_main_t * vm)
286 {
287     vlib_thread_main_t * tm = vlib_get_thread_main();
288     dpdk_main_t * dm = &dpdk_main;
289
290     vlib_cli_output(vm,
291                     "dpdk:   (0x%04x) enabled:%d monitor:%d drop_all:%d\n"
292                     "  dpdk_queue_hi_thresh          %d\n"
293                     "  consec_full_frames_hi_thresh  %d\n"
294                     "---------\n"
295                     "worker: (0x%04x) enabled:%d monitor:%d\n"
296                     "  worker_queue_hi_thresh        %d\n",
297                     dm->efd.enabled,
298                     ((dm->efd.enabled & DPDK_EFD_DISCARD_ENABLED) ? 1:0),
299                     ((dm->efd.enabled & DPDK_EFD_MONITOR_ENABLED) ? 1:0),
300                     ((dm->efd.enabled & DPDK_EFD_DROPALL_ENABLED) ? 1:0),
301                     dm->efd.queue_hi_thresh,
302                     dm->efd.consec_full_frames_hi_thresh,
303                     tm->efd.enabled,
304                     ((tm->efd.enabled & VLIB_EFD_DISCARD_ENABLED) ? 1:0),
305                     ((dm->efd.enabled & VLIB_EFD_MONITOR_ENABLED) ? 1:0),
306                     tm->efd.queue_hi_thresh);
307     vlib_cli_output(vm,
308                     "---------\n"
309                     "ip_prec_bitmap   0x%02x\n"
310                     "mpls_exp_bitmap  0x%02x\n"
311                     "vlan_cos_bitmap  0x%02x\n",
312                     tm->efd.ip_prec_bitmap,
313                     tm->efd.mpls_exp_bitmap,
314                     tm->efd.vlan_cos_bitmap);
315 }
316
317 static clib_error_t *
318 show_efd (vlib_main_t * vm,
319           unformat_input_t * input,
320           vlib_cli_command_t * cmd)
321 {
322
323     if (unformat(input, "config")) {
324         show_efd_config(vm);
325     } else if (unformat(input, "dpdk")) {
326         dpdk_main_t * dm = &dpdk_main;
327         dpdk_device_t * xd;
328         u32 device_id = ~0;
329
330         unformat(input, "device %d", &device_id);
331         vec_foreach (xd, dm->devices) {
332             if ((xd->device_index == device_id) || (device_id == ~0)) {
333                 show_dpdk_device_stats(vm, xd);
334             }
335         }
336     } else if (unformat(input, "worker")) {
337         vlib_thread_main_t * tm = vlib_get_thread_main();
338         vlib_frame_queue_t *fq;
339         vlib_thread_registration_t * tr;
340         int thread_id;
341         u32 num_workers = 0;
342         u32 first_worker_index = 0;
343         uword * p;
344
345         p = hash_get_mem (tm->thread_registrations_by_name, "workers");
346         ASSERT (p);
347         tr = (vlib_thread_registration_t *) p[0];
348         if (tr)
349           {
350             num_workers = tr->count;
351             first_worker_index = tr->first_index;
352           }
353
354         vlib_cli_output(vm,
355                         "num_workers               %d\n"
356                         "first_worker_index        %d\n"
357                         "vlib_frame_queues[%d]:\n",
358                         num_workers,
359                         first_worker_index,
360                         tm->n_vlib_mains);
361
362         for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) {
363             fq = vlib_frame_queues[thread_id];
364             if (fq) {
365                 vlib_cli_output(vm,
366                                 "%2d: frames_queued         %u\n"
367                                 "    frames_queued_hint    %u\n"
368                                 "    enqueue_full_events   %u\n"
369                                 "    enqueue_efd_discards  %u\n",
370                                 thread_id,
371                                 (fq->tail - fq->head),
372                                 (fq->tail - fq->head_hint),
373                                 fq->enqueue_full_events,
374                                 fq->enqueue_efd_discards);
375             }
376         }
377     } else if (unformat(input, "help")) {
378         vlib_cli_output(vm, "Usage: show efd config | "
379                         "dpdk [device <id>] | worker\n");
380     } else {
381         show_efd_config(vm);
382     }
383
384     return 0;
385 }
386
387 VLIB_CLI_COMMAND (show_efd_command, static) = {
388   .path = "show efd",
389   .short_help = "Show efd [device <id>] | [config]",
390   .function = show_efd,
391 };
392
393 static clib_error_t *
394 clear_efd (vlib_main_t * vm,
395            unformat_input_t * input,
396            vlib_cli_command_t * cmd)
397 {
398     dpdk_main_t * dm = &dpdk_main;
399     dpdk_device_t * xd;
400     vlib_thread_main_t * tm = vlib_get_thread_main();
401     vlib_frame_queue_t *fq;
402     int thread_id;
403
404     vec_foreach (xd, dm->devices) {
405         xd->efd_agent.last_burst_sz = 0;
406         xd->efd_agent.max_burst_sz = 0;
407         xd->efd_agent.full_frames_cnt = 0;
408         xd->efd_agent.consec_full_frames_cnt = 0;
409         xd->efd_agent.congestion_cnt = 0;
410         xd->efd_agent.last_poll_time = 0;
411         xd->efd_agent.max_poll_delay = 0;
412         xd->efd_agent.discard_cnt = 0;
413         xd->efd_agent.total_packet_cnt = 0;
414     }
415
416     for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) {
417         fq = vlib_frame_queues[thread_id];
418         if (fq) {
419             fq->enqueue_full_events = 0;
420             fq->enqueue_efd_discards = 0;
421         }
422     }
423
424     return 0;
425 }
426
427 VLIB_CLI_COMMAND (clear_efd_command,static) = {
428   .path = "clear efd",
429   .short_help = "Clear early-fast-discard counters",
430   .function = clear_efd,
431 };
432
433 static clib_error_t *
434 parse_op_and_prec (vlib_main_t *vm, unformat_input_t *input,
435                    vlib_cli_command_t *cmd,
436                    char *prec_type, u8 *prec_bitmap)
437 {
438     clib_error_t * error = NULL;
439     u8 op = 0;
440     u8 prec = 0;
441
442     if (unformat(input, "ge")) {
443         op = EFD_OPERATION_GREATER_OR_EQUAL;
444     } else if (unformat(input, "lt")) {
445         op = EFD_OPERATION_LESS_THAN;
446     } else if (unformat(input, "help")) {
447         vlib_cli_output(vm,
448             "enter operation [ge | lt] and precedence <0-7>)");
449         return (error);
450     } else {
451         return clib_error_return(0, "unknown input `%U'",
452                                   format_unformat_error, input);
453     }
454
455     if (unformat (input, "%u", &prec)) {
456          if (prec > 7) {
457              return clib_error_return(0, "precedence %d is out of range <0-7>",
458                                       prec);
459          }
460     } else {
461         return clib_error_return(0, "unknown input `%U'",
462                                  format_unformat_error, input);
463     }
464
465     set_efd_bitmap(prec_bitmap, prec, op);
466
467     vlib_cli_output(vm,
468         "EFD will be set for %s precedence %s%u%s.",
469         prec_type,
470         (op == EFD_OPERATION_LESS_THAN) ? "less than " : "",
471         prec,
472         (op == EFD_OPERATION_GREATER_OR_EQUAL) ? " and greater" : "");
473
474     return (error);
475 }
476
477
478 static clib_error_t *
479 set_efd (vlib_main_t *vm, unformat_input_t *input,
480           vlib_cli_command_t *cmd)
481 {
482     dpdk_main_t * dm = &dpdk_main;
483     vlib_thread_main_t * tm = vlib_get_thread_main();
484     clib_error_t * error = NULL;
485     vlib_node_runtime_t * rt = vlib_node_get_runtime (vm, dpdk_input_node.index);
486
487     if (unformat(input, "enable")) {
488         if (unformat(input, "dpdk")) {
489             dm->efd.enabled |= DPDK_EFD_DISCARD_ENABLED;
490         } else if (unformat(input, "worker")) {
491             tm->efd.enabled |= VLIB_EFD_DISCARD_ENABLED;
492         } else if (unformat(input, "monitor")) {
493             dm->efd.enabled |= DPDK_EFD_MONITOR_ENABLED;
494             tm->efd.enabled |= VLIB_EFD_MONITOR_ENABLED;
495         } else if (unformat(input, "drop_all")) {
496             dm->efd.enabled |= DPDK_EFD_DROPALL_ENABLED;
497         } else if (unformat(input, "default")) {
498             dm->efd.enabled = (DPDK_EFD_DISCARD_ENABLED |
499                                DPDK_EFD_MONITOR_ENABLED);
500             tm->efd.enabled = (VLIB_EFD_DISCARD_ENABLED |
501                                VLIB_EFD_MONITOR_ENABLED);
502         } else {
503             return clib_error_return(0, "Usage: set efd enable [dpdk | "
504                                      "worker | monitor | drop_all | default]");
505         }
506     } else if (unformat(input, "disable")) {
507         if (unformat(input, "dpdk")) {
508             dm->efd.enabled &= ~DPDK_EFD_DISCARD_ENABLED;
509         } else if (unformat(input, "worker")) {
510             tm->efd.enabled &= ~VLIB_EFD_DISCARD_ENABLED;
511         } else if (unformat(input, "monitor")) {
512             dm->efd.enabled &= ~DPDK_EFD_MONITOR_ENABLED;
513             tm->efd.enabled &= ~VLIB_EFD_MONITOR_ENABLED;
514         } else if (unformat(input, "drop_all")) {
515             dm->efd.enabled &= ~DPDK_EFD_DROPALL_ENABLED;
516         } else  if (unformat(input, "all")) {
517             dm->efd.enabled = 0;
518             tm->efd.enabled = 0;
519         } else {
520             return clib_error_return(0, "Usage: set efd disable [dpdk | "
521                                      "worker | monitor | drop_all | all]");
522         }
523     } else if (unformat(input, "worker_queue_hi_thresh")) {
524         u32 mark;
525         if (unformat (input, "%u", &mark)) {
526             tm->efd.queue_hi_thresh = mark;
527         } else {
528             return clib_error_return(0, "unknown input `%U'",
529                                      format_unformat_error, input);
530         }
531     } else if (unformat(input, "dpdk_device_hi_thresh")) {
532         u32 thresh;
533         if (unformat (input, "%u", &thresh)) {
534             dm->efd.queue_hi_thresh = thresh;
535         } else {
536             return clib_error_return(0, "unknown input `%U'",
537                                      format_unformat_error, input);
538         }
539     } else if (unformat(input, "consec_full_frames_hi_thresh")) {
540         u32 thresh;
541         if (unformat (input, "%u", &thresh)) {
542             dm->efd.consec_full_frames_hi_thresh = thresh;
543         } else {
544             return clib_error_return(0, "unknown input `%U'",
545                                      format_unformat_error, input);
546         }
547     } else if (unformat(input, "ip-prec")) {
548         return (parse_op_and_prec(vm, input, cmd,
549                                  "ip", &tm->efd.ip_prec_bitmap));
550     } else if (unformat(input, "mpls-exp")) {
551         return (parse_op_and_prec(vm, input, cmd,
552                                  "mpls", &tm->efd.mpls_exp_bitmap));
553     } else if (unformat(input, "vlan-cos")) {
554         return (parse_op_and_prec(vm, input, cmd,
555                                  "vlan", &tm->efd.vlan_cos_bitmap));
556     } else if (unformat(input, "help")) {
557         vlib_cli_output(vm,
558             "Usage:\n"
559             "  set efd enable <dpdk | worker | monitor | drop_all | default> |\n"
560             "  set efd disable <dpdk | worker | monitor | drop_all | all> |\n"
561             "  set efd <ip-prec | mpls-exp | vlan-cos> <ge | lt> <0-7>\n"
562             "  set efd worker_queue_hi_thresh <0-32> |\n"
563             "  set efd dpdk_device_hi_thresh <0-%d> |\n"
564             "  set efd consec_full_frames_hi_thresh <count> |\n",
565             DPDK_NB_RX_DESC_10GE);
566     } else {
567         return clib_error_return(0, "unknown input `%U'",
568                                   format_unformat_error, input);
569     }
570
571     if (dm->efd.enabled)
572         rt->function = dpdk_input_efd_multiarch_select();
573     else if (dm->use_rss)
574         rt->function = dpdk_input_rss_multiarch_select();
575     else
576         rt->function = dpdk_input_multiarch_select();
577
578     return error;
579 }
580
581 VLIB_CLI_COMMAND (cmd_set_efd,static) = {
582     .path = "set efd",
583     .short_help = "set early-fast-discard commands",
584     .function = set_efd,
585 };
586
587 static clib_error_t *
588 set_dpdk_if_desc (vlib_main_t *vm, unformat_input_t *input,
589           vlib_cli_command_t *cmd)
590 {
591   unformat_input_t _line_input, * line_input = &_line_input;
592   dpdk_main_t * dm = &dpdk_main;
593   vnet_hw_interface_t * hw;
594   dpdk_device_t * xd;
595   u32 hw_if_index = (u32) ~0;
596   u32 nb_rx_desc = (u32) ~0;
597   u32 nb_tx_desc = (u32) ~0;
598   clib_error_t * rv;
599
600   if (! unformat_user (input, unformat_line_input, line_input))
601     return 0;
602
603   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
604     if (unformat (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
605                   &hw_if_index))
606       ;
607     else if (unformat (line_input, "tx %d", &nb_tx_desc))
608       ;
609     else if (unformat (line_input, "rx %d", &nb_rx_desc))
610       ;
611     else
612       return clib_error_return (0, "parse error: '%U'",
613                                 format_unformat_error, line_input);
614   }
615
616   unformat_free (line_input);
617
618   if (hw_if_index == (u32) ~0)
619     return clib_error_return (0, "please specify valid interface name");
620
621   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
622   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
623
624   if (xd->dev_type != VNET_DPDK_DEV_ETH)
625     return clib_error_return (0, "number of descriptors can be set only for "
626                               "physical devices");
627
628   if ((nb_rx_desc == (u32) ~0 || nb_rx_desc == xd->nb_rx_desc) &&
629       (nb_tx_desc == (u32) ~0 || nb_tx_desc == xd->nb_tx_desc))
630     return clib_error_return (0, "nothing changed");
631
632   if (nb_rx_desc != (u32) ~0)
633         xd->nb_rx_desc = nb_rx_desc;
634
635   if (nb_tx_desc != (u32) ~0)
636         xd->nb_rx_desc = nb_rx_desc;
637
638   rv = dpdk_port_setup(dm, xd);
639
640   return rv < 0 ? rv : 0;
641 }
642
643 VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = {
644     .path = "set dpdk interface descriptors",
645     .short_help = "set dpdk interface descriptors <if-name> [rx <n>] [tx <n>]",
646     .function = set_dpdk_if_desc,
647 };
648
649 static clib_error_t *
650 show_dpdk_if_placement (vlib_main_t *vm, unformat_input_t *input,
651           vlib_cli_command_t *cmd)
652 {
653   vlib_thread_main_t * tm = vlib_get_thread_main();
654   dpdk_main_t * dm = &dpdk_main;
655   dpdk_device_and_queue_t * dq;
656   int cpu;
657
658   if (tm->n_vlib_mains == 1)
659     vlib_cli_output(vm, "All interfaces are handled by main thread");
660
661   for(cpu = 0; cpu < vec_len(dm->devices_by_cpu); cpu++)
662     {
663       if (vec_len(dm->devices_by_cpu[cpu]))
664         vlib_cli_output(vm, "Thread %u (%s at lcore %u):", cpu,
665                         vlib_worker_threads[cpu].name,
666                         vlib_worker_threads[cpu].dpdk_lcore_id);
667
668       vec_foreach(dq, dm->devices_by_cpu[cpu])
669         {
670           u32 hw_if_index = dm->devices[dq->device].vlib_hw_if_index;
671           vnet_hw_interface_t * hi =  vnet_get_hw_interface(dm->vnet_main, hw_if_index);
672           vlib_cli_output(vm, "  %v queue %u", hi->name, dq->queue_id);
673         }
674     }
675   return 0;
676 }
677
678 VLIB_CLI_COMMAND (cmd_show_dpdk_if_placement,static) = {
679     .path = "show dpdk interface placement",
680     .short_help = "show dpdk interface placement",
681     .function = show_dpdk_if_placement,
682 };
683
684 static int
685 dpdk_device_queue_sort(void * a1, void * a2)
686 {
687   dpdk_device_and_queue_t * dq1 = a1;
688   dpdk_device_and_queue_t * dq2 = a2;
689
690   if (dq1->device > dq2->device)
691     return 1;
692   else if (dq1->device < dq2->device)
693     return -1;
694   else if (dq1->queue_id > dq2->queue_id)
695     return 1;
696   else if (dq1->queue_id < dq2->queue_id)
697     return -1;
698   else
699     return 0;
700 }
701
702 static clib_error_t *
703 set_dpdk_if_placement (vlib_main_t *vm, unformat_input_t *input,
704           vlib_cli_command_t *cmd)
705 {
706   unformat_input_t _line_input, * line_input = &_line_input;
707   dpdk_main_t * dm = &dpdk_main;
708   dpdk_device_and_queue_t * dq;
709   vnet_hw_interface_t * hw;
710   dpdk_device_t * xd;
711   u32 hw_if_index = (u32) ~0;
712   u32 queue = (u32) 0;
713   u32 cpu = (u32) ~0;
714   int i;
715
716   if (! unformat_user (input, unformat_line_input, line_input))
717     return 0;
718
719   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
720     if (unformat (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
721                   &hw_if_index))
722       ;
723     else if (unformat (line_input, "queue %d", &queue))
724       ;
725     else if (unformat (line_input, "thread %d", &cpu))
726       ;
727     else
728       return clib_error_return (0, "parse error: '%U'",
729                                 format_unformat_error, line_input);
730   }
731
732   unformat_free (line_input);
733
734   if (hw_if_index == (u32) ~0)
735     return clib_error_return (0, "please specify valid interface name");
736
737   if (cpu < dm->input_cpu_first_index ||
738       cpu >= (dm->input_cpu_first_index + dm->input_cpu_count))
739     return clib_error_return (0, "please specify valid thread id");
740
741   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
742   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
743
744   for(i = 0; i < vec_len(dm->devices_by_cpu); i++)
745     {
746       vec_foreach(dq, dm->devices_by_cpu[i])
747         {
748           if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index &&
749               queue == dq->queue_id)
750             {
751               if (cpu == i) /* nothing to do */
752                 return 0;
753
754               vec_del1(dm->devices_by_cpu[i], dq - dm->devices_by_cpu[i]);
755               vec_add2(dm->devices_by_cpu[cpu], dq, 1);
756               dq->queue_id = queue;
757               dq->device = xd->device_index;
758               xd->cpu_socket_id_by_queue[queue] =
759                 rte_lcore_to_socket_id(vlib_worker_threads[cpu].dpdk_lcore_id);
760
761               vec_sort_with_function(dm->devices_by_cpu[i],
762                                      dpdk_device_queue_sort);
763
764               vec_sort_with_function(dm->devices_by_cpu[cpu],
765                                      dpdk_device_queue_sort);
766
767               if (vec_len(dm->devices_by_cpu[i]) == 0)
768                 vlib_node_set_state (vlib_mains[i], dpdk_input_node.index,
769                                      VLIB_NODE_STATE_DISABLED);
770
771               if (vec_len(dm->devices_by_cpu[cpu]) == 1)
772                 vlib_node_set_state (vlib_mains[cpu], dpdk_input_node.index,
773                                      VLIB_NODE_STATE_POLLING);
774
775               return 0;
776             }
777         }
778     }
779
780   return clib_error_return (0, "not found");
781 }
782
783 VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = {
784     .path = "set dpdk interface placement",
785     .short_help = "set dpdk interface placement <if-name> [queue <n>]  thread <n>",
786     .function = set_dpdk_if_placement,
787 };
788
789 clib_error_t *
790 dpdk_cli_init (vlib_main_t * vm)
791 {
792   return 0;
793 }
794
795 VLIB_INIT_FUNCTION (dpdk_cli_init);