dpdk: remove support for dpdk 16.04
[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/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, vlib_cli_command_t * cmd)
31 {
32   dpdk_main_t *dm = &dpdk_main;
33   u8 *filename;
34   u32 max;
35   int matched = 0;
36   clib_error_t *error = 0;
37
38   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
39     {
40       if (unformat (input, "on"))
41         {
42           if (dm->tx_pcap_enable == 0)
43             {
44               if (dm->pcap_filename == 0)
45                 dm->pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
46
47               memset (&dm->pcap_main, 0, sizeof (dm->pcap_main));
48               dm->pcap_main.file_name = (char *) dm->pcap_filename;
49               dm->pcap_main.n_packets_to_capture = 100;
50               if (dm->pcap_pkts_to_capture)
51                 dm->pcap_main.n_packets_to_capture = dm->pcap_pkts_to_capture;
52
53               dm->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
54               dm->tx_pcap_enable = 1;
55               matched = 1;
56               vlib_cli_output (vm, "pcap tx capture on...");
57             }
58           else
59             {
60               vlib_cli_output (vm, "pcap tx capture already on...");
61             }
62           matched = 1;
63         }
64       else if (unformat (input, "off"))
65         {
66           if (dm->tx_pcap_enable)
67             {
68               vlib_cli_output (vm, "captured %d pkts...",
69                                dm->pcap_main.n_packets_captured + 1);
70               if (dm->pcap_main.n_packets_captured)
71                 {
72                   dm->pcap_main.n_packets_to_capture =
73                     dm->pcap_main.n_packets_captured;
74                   error = pcap_write (&dm->pcap_main);
75                   if (error)
76                     clib_error_report (error);
77                   else
78                     vlib_cli_output (vm, "saved to %s...", dm->pcap_filename);
79                 }
80             }
81           else
82             {
83               vlib_cli_output (vm, "pcap tx capture already off...");
84             }
85
86           dm->tx_pcap_enable = 0;
87           matched = 1;
88         }
89       else if (unformat (input, "max %d", &max))
90         {
91           dm->pcap_pkts_to_capture = max;
92           matched = 1;
93         }
94
95       else if (unformat (input, "intfc %U",
96                          unformat_vnet_sw_interface, dm->vnet_main,
97                          &dm->pcap_sw_if_index))
98         matched = 1;
99       else if (unformat (input, "intfc any"))
100         {
101           dm->pcap_sw_if_index = 0;
102           matched = 1;
103         }
104       else if (unformat (input, "file %s", &filename))
105         {
106           u8 *chroot_filename;
107           /* Brain-police user path input */
108           if (strstr ((char *) filename, "..")
109               || 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 /* *INDENT-OFF* */
151 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
152     .path = "pcap tx trace",
153     .short_help =
154     "pcap tx trace on off max <nn> intfc <intfc> file <name> status",
155     .function = pcap_trace_command_fn,
156 };
157 /* *INDENT-ON* */
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_avail_count (rmp);
173           unsigned free_count = rte_mempool_in_use_count (rmp);
174
175           vlib_cli_output (vm,
176                            "name=\"%s\"  available = %7d allocated = %7d total = %7d\n",
177                            rmp->name, (u32) count, (u32) free_count,
178                            (u32) (count + free_count));
179         }
180       else
181         {
182           vlib_cli_output (vm, "rte_mempool is NULL (!)\n");
183         }
184     }
185   return 0;
186 }
187
188 /* *INDENT-OFF* */
189 VLIB_CLI_COMMAND (cmd_show_dpdk_bufferr,static) = {
190     .path = "show dpdk buffer",
191     .short_help = "show dpdk buffer state",
192     .function = show_dpdk_buffer,
193     .is_mp_safe = 1,
194 };
195 /* *INDENT-ON* */
196
197 static clib_error_t *
198 test_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
199                   vlib_cli_command_t * cmd)
200 {
201   static u32 *allocated_buffers;
202   u32 n_alloc = 0;
203   u32 n_free = 0;
204   u32 first, actual_alloc;
205
206   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
207     {
208       if (unformat (input, "allocate %d", &n_alloc))
209         ;
210       else if (unformat (input, "free %d", &n_free))
211         ;
212       else
213         break;
214     }
215
216   if (n_free)
217     {
218       if (vec_len (allocated_buffers) < n_free)
219         return clib_error_return (0, "Can't free %d, only %d allocated",
220                                   n_free, vec_len (allocated_buffers));
221
222       first = vec_len (allocated_buffers) - n_free;
223       vlib_buffer_free (vm, allocated_buffers + first, n_free);
224       _vec_len (allocated_buffers) = first;
225     }
226   if (n_alloc)
227     {
228       first = vec_len (allocated_buffers);
229       vec_validate (allocated_buffers,
230                     vec_len (allocated_buffers) + n_alloc - 1);
231
232       actual_alloc = vlib_buffer_alloc (vm, allocated_buffers + first,
233                                         n_alloc);
234       _vec_len (allocated_buffers) = first + actual_alloc;
235
236       if (actual_alloc < n_alloc)
237         vlib_cli_output (vm, "WARNING: only allocated %d buffers",
238                          actual_alloc);
239     }
240
241   vlib_cli_output (vm, "Currently %d buffers allocated",
242                    vec_len (allocated_buffers));
243
244   if (allocated_buffers && vec_len (allocated_buffers) == 0)
245     vec_free (allocated_buffers);
246
247   return 0;
248 }
249
250 /* *INDENT-OFF* */
251 VLIB_CLI_COMMAND (cmd_test_dpdk_buffer,static) = {
252     .path = "test dpdk buffer",
253     .short_help = "test dpdk buffer [allocate <nn>][free <nn>]",
254     .function = test_dpdk_buffer,
255     .is_mp_safe = 1,
256 };
257 /* *INDENT-ON* */
258
259 static void
260 show_dpdk_device_stats (vlib_main_t * vm, dpdk_device_t * xd)
261 {
262   vlib_cli_output (vm,
263                    "device_index %d\n"
264                    "  last_burst_sz           %d\n"
265                    "  max_burst_sz            %d\n"
266                    "  full_frames_cnt         %u\n"
267                    "  consec_full_frames_cnt  %u\n"
268                    "  congestion_cnt          %d\n"
269                    "  last_poll_time          %llu\n"
270                    "  max_poll_delay          %llu\n"
271                    "  discard_cnt             %u\n"
272                    "  total_packet_cnt        %u\n",
273                    xd->device_index,
274                    xd->efd_agent.last_burst_sz,
275                    xd->efd_agent.max_burst_sz,
276                    xd->efd_agent.full_frames_cnt,
277                    xd->efd_agent.consec_full_frames_cnt,
278                    xd->efd_agent.congestion_cnt,
279                    xd->efd_agent.last_poll_time,
280                    xd->efd_agent.max_poll_delay,
281                    xd->efd_agent.discard_cnt, xd->efd_agent.total_packet_cnt);
282
283   u32 device_queue_sz = rte_eth_rx_queue_count (xd->device_index,
284                                                 0 /* queue_id */ );
285   vlib_cli_output (vm, "  device_queue_sz         %u\n", device_queue_sz);
286 }
287
288 static void
289 show_efd_config (vlib_main_t * vm)
290 {
291   vlib_thread_main_t *tm = vlib_get_thread_main ();
292   dpdk_main_t *dm = &dpdk_main;
293
294   vlib_cli_output (vm,
295                    "dpdk:   (0x%04x) enabled:%d monitor:%d drop_all:%d\n"
296                    "  dpdk_queue_hi_thresh          %d\n"
297                    "  consec_full_frames_hi_thresh  %d\n"
298                    "---------\n"
299                    "worker: (0x%04x) enabled:%d monitor:%d\n"
300                    "  worker_queue_hi_thresh        %d\n",
301                    dm->efd.enabled,
302                    ((dm->efd.enabled & DPDK_EFD_DISCARD_ENABLED) ? 1 : 0),
303                    ((dm->efd.enabled & DPDK_EFD_MONITOR_ENABLED) ? 1 : 0),
304                    ((dm->efd.enabled & DPDK_EFD_DROPALL_ENABLED) ? 1 : 0),
305                    dm->efd.queue_hi_thresh,
306                    dm->efd.consec_full_frames_hi_thresh,
307                    tm->efd.enabled,
308                    ((tm->efd.enabled & VLIB_EFD_DISCARD_ENABLED) ? 1 : 0),
309                    ((dm->efd.enabled & VLIB_EFD_MONITOR_ENABLED) ? 1 : 0),
310                    tm->efd.queue_hi_thresh);
311   vlib_cli_output (vm,
312                    "---------\n"
313                    "ip_prec_bitmap   0x%02x\n"
314                    "mpls_exp_bitmap  0x%02x\n"
315                    "vlan_cos_bitmap  0x%02x\n",
316                    tm->efd.ip_prec_bitmap,
317                    tm->efd.mpls_exp_bitmap, tm->efd.vlan_cos_bitmap);
318 }
319
320 static clib_error_t *
321 show_efd (vlib_main_t * vm,
322           unformat_input_t * input, vlib_cli_command_t * cmd)
323 {
324
325   if (unformat (input, "config"))
326     {
327       show_efd_config (vm);
328     }
329   else if (unformat (input, "dpdk"))
330     {
331       dpdk_main_t *dm = &dpdk_main;
332       dpdk_device_t *xd;
333       u32 device_id = ~0;
334
335       (void) unformat (input, "device %d", &device_id);
336         /* *INDENT-OFF* */
337         vec_foreach (xd, dm->devices)
338           {
339             if ((xd->device_index == device_id) || (device_id == ~0))
340               {
341                 show_dpdk_device_stats(vm, xd);
342               }
343           }
344         /* *INDENT-ON* */
345     }
346   else if (unformat (input, "worker"))
347     {
348       vlib_thread_main_t *tm = vlib_get_thread_main ();
349       vlib_frame_queue_t *fq;
350       vlib_thread_registration_t *tr;
351       int thread_id;
352       u32 num_workers = 0;
353       u32 first_worker_index = 0;
354       uword *p;
355
356       p = hash_get_mem (tm->thread_registrations_by_name, "workers");
357       ASSERT (p);
358       tr = (vlib_thread_registration_t *) p[0];
359       if (tr)
360         {
361           num_workers = tr->count;
362           first_worker_index = tr->first_index;
363         }
364
365       vlib_cli_output (vm,
366                        "num_workers               %d\n"
367                        "first_worker_index        %d\n"
368                        "vlib_frame_queues[%d]:\n",
369                        num_workers, first_worker_index, tm->n_vlib_mains);
370
371       for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++)
372         {
373           fq = vlib_frame_queues[thread_id];
374           if (fq)
375             {
376               vlib_cli_output (vm,
377                                "%2d: frames_queued         %u\n"
378                                "    frames_queued_hint    %u\n"
379                                "    enqueue_full_events   %u\n"
380                                "    enqueue_efd_discards  %u\n",
381                                thread_id,
382                                (fq->tail - fq->head),
383                                (fq->tail - fq->head_hint),
384                                fq->enqueue_full_events,
385                                fq->enqueue_efd_discards);
386             }
387         }
388     }
389   else if (unformat (input, "help"))
390     {
391       vlib_cli_output (vm, "Usage: show efd config | "
392                        "dpdk [device <id>] | worker\n");
393     }
394   else
395     {
396       show_efd_config (vm);
397     }
398
399   return 0;
400 }
401
402 /* *INDENT-OFF* */
403 VLIB_CLI_COMMAND (show_efd_command, static) = {
404   .path = "show efd",
405   .short_help = "Show efd [device <id>] | [config]",
406   .function = show_efd,
407 };
408 /* *INDENT-ON* */
409
410 static clib_error_t *
411 clear_efd (vlib_main_t * vm,
412            unformat_input_t * input, vlib_cli_command_t * cmd)
413 {
414   dpdk_main_t *dm = &dpdk_main;
415   dpdk_device_t *xd;
416   vlib_thread_main_t *tm = vlib_get_thread_main ();
417   vlib_frame_queue_t *fq;
418   int thread_id;
419
420     /* *INDENT-OFF* */
421     vec_foreach (xd, dm->devices)
422       {
423         xd->efd_agent.last_burst_sz = 0;
424         xd->efd_agent.max_burst_sz = 0;
425         xd->efd_agent.full_frames_cnt = 0;
426         xd->efd_agent.consec_full_frames_cnt = 0;
427         xd->efd_agent.congestion_cnt = 0;
428         xd->efd_agent.last_poll_time = 0;
429         xd->efd_agent.max_poll_delay = 0;
430         xd->efd_agent.discard_cnt = 0;
431         xd->efd_agent.total_packet_cnt = 0;
432       }
433     /* *INDENT-ON* */
434
435   for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++)
436     {
437       fq = vlib_frame_queues[thread_id];
438       if (fq)
439         {
440           fq->enqueue_full_events = 0;
441           fq->enqueue_efd_discards = 0;
442         }
443     }
444
445   return 0;
446 }
447
448 /* *INDENT-OFF* */
449 VLIB_CLI_COMMAND (clear_efd_command,static) = {
450   .path = "clear efd",
451   .short_help = "Clear early-fast-discard counters",
452   .function = clear_efd,
453 };
454 /* *INDENT-ON* */
455
456 static clib_error_t *
457 parse_op_and_prec (vlib_main_t * vm, unformat_input_t * input,
458                    vlib_cli_command_t * cmd,
459                    char *prec_type, u8 * prec_bitmap)
460 {
461   clib_error_t *error = NULL;
462   u8 op = 0;
463   u8 prec = 0;
464
465   if (unformat (input, "ge"))
466     {
467       op = EFD_OPERATION_GREATER_OR_EQUAL;
468     }
469   else if (unformat (input, "lt"))
470     {
471       op = EFD_OPERATION_LESS_THAN;
472     }
473   else if (unformat (input, "help"))
474     {
475       vlib_cli_output (vm, "enter operation [ge | lt] and precedence <0-7>)");
476       return (error);
477     }
478   else
479     {
480       return clib_error_return (0, "unknown input `%U'",
481                                 format_unformat_error, input);
482     }
483
484   if (unformat (input, "%u", &prec))
485     {
486       if (prec > 7)
487         {
488           return clib_error_return (0, "precedence %d is out of range <0-7>",
489                                     prec);
490         }
491     }
492   else
493     {
494       return clib_error_return (0, "unknown input `%U'",
495                                 format_unformat_error, input);
496     }
497
498   set_efd_bitmap (prec_bitmap, prec, op);
499
500   vlib_cli_output (vm,
501                    "EFD will be set for %s precedence %s%u%s.",
502                    prec_type,
503                    (op == EFD_OPERATION_LESS_THAN) ? "less than " : "",
504                    prec,
505                    (op ==
506                     EFD_OPERATION_GREATER_OR_EQUAL) ? " and greater" : "");
507
508   return (error);
509 }
510
511
512 static clib_error_t *
513 set_efd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
514 {
515   dpdk_main_t *dm = &dpdk_main;
516   vlib_thread_main_t *tm = vlib_get_thread_main ();
517   clib_error_t *error = NULL;
518   vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, dpdk_input_node.index);
519
520   if (unformat (input, "enable"))
521     {
522       if (unformat (input, "dpdk"))
523         {
524           dm->efd.enabled |= DPDK_EFD_DISCARD_ENABLED;
525         }
526       else if (unformat (input, "worker"))
527         {
528           tm->efd.enabled |= VLIB_EFD_DISCARD_ENABLED;
529         }
530       else if (unformat (input, "monitor"))
531         {
532           dm->efd.enabled |= DPDK_EFD_MONITOR_ENABLED;
533           tm->efd.enabled |= VLIB_EFD_MONITOR_ENABLED;
534         }
535       else if (unformat (input, "drop_all"))
536         {
537           dm->efd.enabled |= DPDK_EFD_DROPALL_ENABLED;
538         }
539       else if (unformat (input, "default"))
540         {
541           dm->efd.enabled = (DPDK_EFD_DISCARD_ENABLED |
542                              DPDK_EFD_MONITOR_ENABLED);
543           tm->efd.enabled = (VLIB_EFD_DISCARD_ENABLED |
544                              VLIB_EFD_MONITOR_ENABLED);
545         }
546       else
547         {
548           return clib_error_return (0, "Usage: set efd enable [dpdk | "
549                                     "worker | monitor | drop_all | default]");
550         }
551     }
552   else if (unformat (input, "disable"))
553     {
554       if (unformat (input, "dpdk"))
555         {
556           dm->efd.enabled &= ~DPDK_EFD_DISCARD_ENABLED;
557         }
558       else if (unformat (input, "worker"))
559         {
560           tm->efd.enabled &= ~VLIB_EFD_DISCARD_ENABLED;
561         }
562       else if (unformat (input, "monitor"))
563         {
564           dm->efd.enabled &= ~DPDK_EFD_MONITOR_ENABLED;
565           tm->efd.enabled &= ~VLIB_EFD_MONITOR_ENABLED;
566         }
567       else if (unformat (input, "drop_all"))
568         {
569           dm->efd.enabled &= ~DPDK_EFD_DROPALL_ENABLED;
570         }
571       else if (unformat (input, "all"))
572         {
573           dm->efd.enabled = 0;
574           tm->efd.enabled = 0;
575         }
576       else
577         {
578           return clib_error_return (0, "Usage: set efd disable [dpdk | "
579                                     "worker | monitor | drop_all | all]");
580         }
581     }
582   else if (unformat (input, "worker_queue_hi_thresh"))
583     {
584       u32 mark;
585       if (unformat (input, "%u", &mark))
586         {
587           tm->efd.queue_hi_thresh = mark;
588         }
589       else
590         {
591           return clib_error_return (0, "unknown input `%U'",
592                                     format_unformat_error, input);
593         }
594     }
595   else if (unformat (input, "dpdk_device_hi_thresh"))
596     {
597       u32 thresh;
598       if (unformat (input, "%u", &thresh))
599         {
600           dm->efd.queue_hi_thresh = thresh;
601         }
602       else
603         {
604           return clib_error_return (0, "unknown input `%U'",
605                                     format_unformat_error, input);
606         }
607     }
608   else if (unformat (input, "consec_full_frames_hi_thresh"))
609     {
610       u32 thresh;
611       if (unformat (input, "%u", &thresh))
612         {
613           dm->efd.consec_full_frames_hi_thresh = thresh;
614         }
615       else
616         {
617           return clib_error_return (0, "unknown input `%U'",
618                                     format_unformat_error, input);
619         }
620     }
621   else if (unformat (input, "ip-prec"))
622     {
623       return (parse_op_and_prec (vm, input, cmd,
624                                  "ip", &tm->efd.ip_prec_bitmap));
625     }
626   else if (unformat (input, "mpls-exp"))
627     {
628       return (parse_op_and_prec (vm, input, cmd,
629                                  "mpls", &tm->efd.mpls_exp_bitmap));
630     }
631   else if (unformat (input, "vlan-cos"))
632     {
633       return (parse_op_and_prec (vm, input, cmd,
634                                  "vlan", &tm->efd.vlan_cos_bitmap));
635     }
636   else if (unformat (input, "help"))
637     {
638       vlib_cli_output (vm,
639                        "Usage:\n"
640                        "  set efd enable <dpdk | worker | monitor | drop_all | default> |\n"
641                        "  set efd disable <dpdk | worker | monitor | drop_all | all> |\n"
642                        "  set efd <ip-prec | mpls-exp | vlan-cos> <ge | lt> <0-7>\n"
643                        "  set efd worker_queue_hi_thresh <0-32> |\n"
644                        "  set efd dpdk_device_hi_thresh <0-%d> |\n"
645                        "  set efd consec_full_frames_hi_thresh <count> |\n",
646                        DPDK_NB_RX_DESC_10GE);
647     }
648   else
649     {
650       return clib_error_return (0, "unknown input `%U'",
651                                 format_unformat_error, input);
652     }
653
654   if (dm->efd.enabled)
655     rt->function = dpdk_input_efd_multiarch_select ();
656   else if (dm->use_rss)
657     rt->function = dpdk_input_rss_multiarch_select ();
658   else
659     rt->function = dpdk_input_multiarch_select ();
660
661   return error;
662 }
663
664 /* *INDENT-OFF* */
665 VLIB_CLI_COMMAND (cmd_set_efd,static) = {
666     .path = "set efd",
667     .short_help = "set early-fast-discard commands",
668     .function = set_efd,
669 };
670 /* *INDENT-ON* */
671
672 static clib_error_t *
673 set_dpdk_if_desc (vlib_main_t * vm, unformat_input_t * input,
674                   vlib_cli_command_t * cmd)
675 {
676   unformat_input_t _line_input, *line_input = &_line_input;
677   dpdk_main_t *dm = &dpdk_main;
678   vnet_hw_interface_t *hw;
679   dpdk_device_t *xd;
680   u32 hw_if_index = (u32) ~ 0;
681   u32 nb_rx_desc = (u32) ~ 0;
682   u32 nb_tx_desc = (u32) ~ 0;
683   clib_error_t *rv;
684
685   if (!unformat_user (input, unformat_line_input, line_input))
686     return 0;
687
688   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
689     {
690       if (unformat
691           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
692            &hw_if_index))
693         ;
694       else if (unformat (line_input, "tx %d", &nb_tx_desc))
695         ;
696       else if (unformat (line_input, "rx %d", &nb_rx_desc))
697         ;
698       else
699         return clib_error_return (0, "parse error: '%U'",
700                                   format_unformat_error, line_input);
701     }
702
703   unformat_free (line_input);
704
705   if (hw_if_index == (u32) ~ 0)
706     return clib_error_return (0, "please specify valid interface name");
707
708   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
709   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
710
711   if ((xd->flags & DPDK_DEVICE_FLAG_PMD) == 0)
712     return clib_error_return (0, "number of descriptors can be set only for "
713                               "physical devices");
714
715   if ((nb_rx_desc == (u32) ~ 0 || nb_rx_desc == xd->nb_rx_desc) &&
716       (nb_tx_desc == (u32) ~ 0 || nb_tx_desc == xd->nb_tx_desc))
717     return clib_error_return (0, "nothing changed");
718
719   if (nb_rx_desc != (u32) ~ 0)
720     xd->nb_rx_desc = nb_rx_desc;
721
722   if (nb_tx_desc != (u32) ~ 0)
723     xd->nb_rx_desc = nb_rx_desc;
724
725   rv = dpdk_port_setup (dm, xd);
726
727   return rv;
728 }
729
730 /* *INDENT-OFF* */
731 VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = {
732     .path = "set dpdk interface descriptors",
733     .short_help = "set dpdk interface descriptors <if-name> [rx <n>] [tx <n>]",
734     .function = set_dpdk_if_desc,
735 };
736 /* *INDENT-ON* */
737
738 static clib_error_t *
739 show_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input,
740                         vlib_cli_command_t * cmd)
741 {
742   vlib_thread_main_t *tm = vlib_get_thread_main ();
743   dpdk_main_t *dm = &dpdk_main;
744   dpdk_device_and_queue_t *dq;
745   int cpu;
746
747   if (tm->n_vlib_mains == 1)
748     vlib_cli_output (vm, "All interfaces are handled by main thread");
749
750   for (cpu = 0; cpu < vec_len (dm->devices_by_cpu); cpu++)
751     {
752       if (vec_len (dm->devices_by_cpu[cpu]))
753         vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu,
754                          vlib_worker_threads[cpu].name,
755                          vlib_worker_threads[cpu].lcore_id);
756
757       /* *INDENT-OFF* */
758       vec_foreach(dq, dm->devices_by_cpu[cpu])
759         {
760           u32 hw_if_index = dm->devices[dq->device].vlib_hw_if_index;
761           vnet_hw_interface_t * hi =  vnet_get_hw_interface(dm->vnet_main, hw_if_index);
762           vlib_cli_output(vm, "  %v queue %u", hi->name, dq->queue_id);
763         }
764       /* *INDENT-ON* */
765     }
766   return 0;
767 }
768
769 /* *INDENT-OFF* */
770 VLIB_CLI_COMMAND (cmd_show_dpdk_if_placement,static) = {
771     .path = "show dpdk interface placement",
772     .short_help = "show dpdk interface placement",
773     .function = show_dpdk_if_placement,
774 };
775 /* *INDENT-ON* */
776
777 static int
778 dpdk_device_queue_sort (void *a1, void *a2)
779 {
780   dpdk_device_and_queue_t *dq1 = a1;
781   dpdk_device_and_queue_t *dq2 = a2;
782
783   if (dq1->device > dq2->device)
784     return 1;
785   else if (dq1->device < dq2->device)
786     return -1;
787   else if (dq1->queue_id > dq2->queue_id)
788     return 1;
789   else if (dq1->queue_id < dq2->queue_id)
790     return -1;
791   else
792     return 0;
793 }
794
795 static clib_error_t *
796 set_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input,
797                        vlib_cli_command_t * cmd)
798 {
799   unformat_input_t _line_input, *line_input = &_line_input;
800   dpdk_main_t *dm = &dpdk_main;
801   dpdk_device_and_queue_t *dq;
802   vnet_hw_interface_t *hw;
803   dpdk_device_t *xd;
804   u32 hw_if_index = (u32) ~ 0;
805   u32 queue = (u32) 0;
806   u32 cpu = (u32) ~ 0;
807   int i;
808
809   if (!unformat_user (input, unformat_line_input, line_input))
810     return 0;
811
812   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
813     {
814       if (unformat
815           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
816            &hw_if_index))
817         ;
818       else if (unformat (line_input, "queue %d", &queue))
819         ;
820       else if (unformat (line_input, "thread %d", &cpu))
821         ;
822       else
823         return clib_error_return (0, "parse error: '%U'",
824                                   format_unformat_error, line_input);
825     }
826
827   unformat_free (line_input);
828
829   if (hw_if_index == (u32) ~ 0)
830     return clib_error_return (0, "please specify valid interface name");
831
832   if (cpu < dm->input_cpu_first_index ||
833       cpu >= (dm->input_cpu_first_index + dm->input_cpu_count))
834     return clib_error_return (0, "please specify valid thread id");
835
836   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
837   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
838
839   for (i = 0; i < vec_len (dm->devices_by_cpu); i++)
840     {
841       /* *INDENT-OFF* */
842       vec_foreach(dq, dm->devices_by_cpu[i])
843         {
844           if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index &&
845               queue == dq->queue_id)
846             {
847               if (cpu == i) /* nothing to do */
848                 return 0;
849
850               vec_del1(dm->devices_by_cpu[i], dq - dm->devices_by_cpu[i]);
851               vec_add2(dm->devices_by_cpu[cpu], dq, 1);
852               dq->queue_id = queue;
853               dq->device = xd->device_index;
854               xd->cpu_socket_id_by_queue[queue] =
855                 rte_lcore_to_socket_id(vlib_worker_threads[cpu].lcore_id);
856
857               vec_sort_with_function(dm->devices_by_cpu[i],
858                                      dpdk_device_queue_sort);
859
860               vec_sort_with_function(dm->devices_by_cpu[cpu],
861                                      dpdk_device_queue_sort);
862
863               if (vec_len(dm->devices_by_cpu[i]) == 0)
864                 vlib_node_set_state (vlib_mains[i], dpdk_input_node.index,
865                                      VLIB_NODE_STATE_DISABLED);
866
867               if (vec_len(dm->devices_by_cpu[cpu]) == 1)
868                 vlib_node_set_state (vlib_mains[cpu], dpdk_input_node.index,
869                                      VLIB_NODE_STATE_POLLING);
870
871               return 0;
872             }
873         }
874       /* *INDENT-ON* */
875     }
876
877   return clib_error_return (0, "not found");
878 }
879
880 /* *INDENT-OFF* */
881 VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = {
882     .path = "set dpdk interface placement",
883     .short_help = "set dpdk interface placement <if-name> [queue <n>]  thread <n>",
884     .function = set_dpdk_if_placement,
885 };
886 /* *INDENT-ON* */
887
888 static clib_error_t *
889 show_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input,
890                              vlib_cli_command_t * cmd)
891 {
892   vlib_thread_main_t *tm = vlib_get_thread_main ();
893   dpdk_main_t *dm = &dpdk_main;
894   dpdk_device_and_queue_t *dq;
895   int cpu;
896
897   if (tm->n_vlib_mains == 1)
898     vlib_cli_output (vm, "All interfaces are handled by main thread");
899
900   for (cpu = 0; cpu < vec_len (dm->devices_by_hqos_cpu); cpu++)
901     {
902       if (vec_len (dm->devices_by_hqos_cpu[cpu]))
903         vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu,
904                          vlib_worker_threads[cpu].name,
905                          vlib_worker_threads[cpu].lcore_id);
906
907       vec_foreach (dq, dm->devices_by_hqos_cpu[cpu])
908       {
909         u32 hw_if_index = dm->devices[dq->device].vlib_hw_if_index;
910         vnet_hw_interface_t *hi =
911           vnet_get_hw_interface (dm->vnet_main, hw_if_index);
912         vlib_cli_output (vm, "  %v queue %u", hi->name, dq->queue_id);
913       }
914     }
915   return 0;
916 }
917
918 /* *INDENT-OFF* */
919 VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos_placement, static) = {
920   .path = "show dpdk interface hqos placement",
921   .short_help = "show dpdk interface hqos placement",
922   .function = show_dpdk_if_hqos_placement,
923 };
924 /* *INDENT-ON* */
925
926 static clib_error_t *
927 set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input,
928                             vlib_cli_command_t * cmd)
929 {
930   unformat_input_t _line_input, *line_input = &_line_input;
931   dpdk_main_t *dm = &dpdk_main;
932   dpdk_device_and_queue_t *dq;
933   vnet_hw_interface_t *hw;
934   dpdk_device_t *xd;
935   u32 hw_if_index = (u32) ~ 0;
936   u32 cpu = (u32) ~ 0;
937   int i;
938
939   if (!unformat_user (input, unformat_line_input, line_input))
940     return 0;
941
942   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
943     {
944       if (unformat
945           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
946            &hw_if_index))
947         ;
948       else if (unformat (line_input, "thread %d", &cpu))
949         ;
950       else
951         return clib_error_return (0, "parse error: '%U'",
952                                   format_unformat_error, line_input);
953     }
954
955   unformat_free (line_input);
956
957   if (hw_if_index == (u32) ~ 0)
958     return clib_error_return (0, "please specify valid interface name");
959
960   if (cpu < dm->hqos_cpu_first_index ||
961       cpu >= (dm->hqos_cpu_first_index + dm->hqos_cpu_count))
962     return clib_error_return (0, "please specify valid thread id");
963
964   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
965   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
966
967   for (i = 0; i < vec_len (dm->devices_by_hqos_cpu); i++)
968     {
969       vec_foreach (dq, dm->devices_by_hqos_cpu[i])
970       {
971         if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index)
972           {
973             if (cpu == i)       /* nothing to do */
974               return 0;
975
976             vec_del1 (dm->devices_by_hqos_cpu[i],
977                       dq - dm->devices_by_hqos_cpu[i]);
978             vec_add2 (dm->devices_by_hqos_cpu[cpu], dq, 1);
979             dq->queue_id = 0;
980             dq->device = xd->device_index;
981
982             vec_sort_with_function (dm->devices_by_hqos_cpu[i],
983                                     dpdk_device_queue_sort);
984
985             vec_sort_with_function (dm->devices_by_hqos_cpu[cpu],
986                                     dpdk_device_queue_sort);
987
988             return 0;
989           }
990       }
991     }
992
993   return clib_error_return (0, "not found");
994 }
995
996 /* *INDENT-OFF* */
997 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_placement, static) = {
998   .path = "set dpdk interface hqos placement",
999   .short_help = "set dpdk interface hqos placement <if-name> thread <n>",
1000   .function = set_dpdk_if_hqos_placement,
1001 };
1002 /* *INDENT-ON* */
1003
1004 static clib_error_t *
1005 set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input,
1006                        vlib_cli_command_t * cmd)
1007 {
1008   unformat_input_t _line_input, *line_input = &_line_input;
1009   dpdk_main_t *dm = &dpdk_main;
1010   vnet_hw_interface_t *hw;
1011   dpdk_device_t *xd;
1012   u32 hw_if_index = (u32) ~ 0;
1013   u32 subport_id = (u32) ~ 0;
1014   u32 pipe_id = (u32) ~ 0;
1015   u32 profile_id = (u32) ~ 0;
1016   int rv;
1017
1018   if (!unformat_user (input, unformat_line_input, line_input))
1019     return 0;
1020
1021   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1022     {
1023       if (unformat
1024           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1025            &hw_if_index))
1026         ;
1027       else if (unformat (line_input, "subport %d", &subport_id))
1028         ;
1029       else if (unformat (line_input, "pipe %d", &pipe_id))
1030         ;
1031       else if (unformat (line_input, "profile %d", &profile_id))
1032         ;
1033       else
1034         return clib_error_return (0, "parse error: '%U'",
1035                                   format_unformat_error, line_input);
1036     }
1037
1038   unformat_free (line_input);
1039
1040   if (hw_if_index == (u32) ~ 0)
1041     return clib_error_return (0, "please specify valid interface name");
1042
1043   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1044   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1045
1046   rv =
1047     rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id,
1048                            profile_id);
1049   if (rv)
1050     return clib_error_return (0, "pipe configuration failed");
1051
1052   return 0;
1053 }
1054
1055 /* *INDENT-OFF* */
1056 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pipe, static) =
1057 {
1058   .path = "set dpdk interface hqos pipe",
1059   .short_help = "set dpdk interface hqos pipe <if-name> subport <n> pipe <n> "
1060                   "profile <n>",
1061   .function = set_dpdk_if_hqos_pipe,
1062 };
1063 /* *INDENT-ON* */
1064
1065 static clib_error_t *
1066 set_dpdk_if_hqos_subport (vlib_main_t * vm, unformat_input_t * input,
1067                           vlib_cli_command_t * cmd)
1068 {
1069   unformat_input_t _line_input, *line_input = &_line_input;
1070   dpdk_main_t *dm = &dpdk_main;
1071   vnet_hw_interface_t *hw;
1072   dpdk_device_t *xd;
1073   u32 hw_if_index = (u32) ~ 0;
1074   u32 subport_id = (u32) ~ 0;
1075   struct rte_sched_subport_params p = {
1076     .tb_rate = 1250000000,      /* 10GbE */
1077     .tb_size = 1000000,
1078     .tc_rate = {1250000000, 1250000000, 1250000000, 1250000000},
1079     .tc_period = 10,
1080   };
1081   int rv;
1082
1083   if (!unformat_user (input, unformat_line_input, line_input))
1084     return 0;
1085
1086   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1087     {
1088       if (unformat
1089           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1090            &hw_if_index))
1091         ;
1092       else if (unformat (line_input, "subport %d", &subport_id))
1093         ;
1094       else if (unformat (line_input, "rate %d", &p.tb_rate))
1095         {
1096           p.tc_rate[0] = p.tb_rate;
1097           p.tc_rate[1] = p.tb_rate;
1098           p.tc_rate[2] = p.tb_rate;
1099           p.tc_rate[3] = p.tb_rate;
1100         }
1101       else if (unformat (line_input, "bktsize %d", &p.tb_size))
1102         ;
1103       else if (unformat (line_input, "tc0 %d", &p.tc_rate[0]))
1104         ;
1105       else if (unformat (line_input, "tc1 %d", &p.tc_rate[1]))
1106         ;
1107       else if (unformat (line_input, "tc2 %d", &p.tc_rate[2]))
1108         ;
1109       else if (unformat (line_input, "tc3 %d", &p.tc_rate[3]))
1110         ;
1111       else if (unformat (line_input, "period %d", &p.tc_period))
1112         ;
1113       else
1114         return clib_error_return (0, "parse error: '%U'",
1115                                   format_unformat_error, line_input);
1116     }
1117
1118   unformat_free (line_input);
1119
1120   if (hw_if_index == (u32) ~ 0)
1121     return clib_error_return (0, "please specify valid interface name");
1122
1123   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1124   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1125
1126   rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, &p);
1127   if (rv)
1128     return clib_error_return (0, "subport configuration failed");
1129
1130   return 0;
1131 }
1132
1133 /* *INDENT-OFF* */
1134 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_subport, static) = {
1135   .path = "set dpdk interface hqos subport",
1136   .short_help = "set dpdk interface hqos subport <if-name> subport <n> "
1137                  "[rate <n>] [bktsize <n>] [tc0 <n>] [tc1 <n>] [tc2 <n>] [tc3 <n>] "
1138                  "[period <n>]",
1139   .function = set_dpdk_if_hqos_subport,
1140 };
1141 /* *INDENT-ON* */
1142
1143 static clib_error_t *
1144 set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input,
1145                         vlib_cli_command_t * cmd)
1146 {
1147   unformat_input_t _line_input, *line_input = &_line_input;
1148   vlib_thread_main_t *tm = vlib_get_thread_main ();
1149   dpdk_main_t *dm = &dpdk_main;
1150   vnet_hw_interface_t *hw;
1151   dpdk_device_t *xd;
1152   u32 hw_if_index = (u32) ~ 0;
1153   u32 entry, tc, queue, val, i;
1154
1155   if (!unformat_user (input, unformat_line_input, line_input))
1156     return 0;
1157
1158   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1159     {
1160       if (unformat
1161           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1162            &hw_if_index))
1163         ;
1164       else if (unformat (line_input, "entry %d", &entry))
1165         ;
1166       else if (unformat (line_input, "tc %d", &tc))
1167         ;
1168       else if (unformat (line_input, "queue %d", &queue))
1169         ;
1170       else
1171         return clib_error_return (0, "parse error: '%U'",
1172                                   format_unformat_error, line_input);
1173     }
1174
1175   unformat_free (line_input);
1176
1177   if (hw_if_index == (u32) ~ 0)
1178     return clib_error_return (0, "please specify valid interface name");
1179   if (entry >= 64)
1180     return clib_error_return (0, "invalid entry");
1181   if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE)
1182     return clib_error_return (0, "invalid traffic class");
1183   if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS)
1184     return clib_error_return (0, "invalid traffic class");
1185
1186   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1187   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1188
1189   /* Detect the set of worker threads */
1190   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1191   vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0];
1192   int worker_thread_first = tr->first_index;
1193   int worker_thread_count = tr->count;
1194
1195   val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
1196   for (i = 0; i < worker_thread_count; i++)
1197     xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val;
1198
1199   return 0;
1200 }
1201
1202 /* *INDENT-OFF* */
1203 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_tctbl, static) = {
1204   .path = "set dpdk interface hqos tctbl",
1205   .short_help = "set dpdk interface hqos tctbl <if-name> entry <n> tc <n> queue <n>",
1206   .function = set_dpdk_if_hqos_tctbl,
1207 };
1208 /* *INDENT-ON* */
1209
1210 static clib_error_t *
1211 set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input,
1212                            vlib_cli_command_t * cmd)
1213 {
1214   unformat_input_t _line_input, *line_input = &_line_input;
1215   vlib_thread_main_t *tm = vlib_get_thread_main ();
1216   dpdk_main_t *dm = &dpdk_main;
1217
1218   /* Device specific data */
1219   struct rte_eth_dev_info dev_info;
1220   dpdk_device_config_t *devconf = 0;
1221   vnet_hw_interface_t *hw;
1222   dpdk_device_t *xd;
1223   u32 hw_if_index = (u32) ~ 0;
1224
1225   /* Detect the set of worker threads */
1226   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1227   vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0];
1228   int worker_thread_first = tr->first_index;
1229   int worker_thread_count = tr->count;
1230
1231   /* Packet field configuration */
1232   u64 mask;
1233   u32 id, offset;
1234
1235   /* HQoS params */
1236   u32 n_subports_per_port, n_pipes_per_subport, tctbl_size;
1237
1238   u32 i;
1239
1240   /* Parse input arguments */
1241   if (!unformat_user (input, unformat_line_input, line_input))
1242     return 0;
1243
1244   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1245     {
1246       if (unformat
1247           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1248            &hw_if_index))
1249         ;
1250       else if (unformat (line_input, "id %d", &id))
1251         ;
1252       else if (unformat (line_input, "offset %d", &offset))
1253         ;
1254       else if (unformat (line_input, "mask %llx", &mask))
1255         ;
1256       else
1257         return clib_error_return (0, "parse error: '%U'",
1258                                   format_unformat_error, line_input);
1259     }
1260
1261   unformat_free (line_input);
1262
1263   /* Get interface */
1264   if (hw_if_index == (u32) ~ 0)
1265     return clib_error_return (0, "please specify valid interface name");
1266
1267   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1268   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1269
1270   rte_eth_dev_info_get (xd->device_index, &dev_info);
1271   if (dev_info.pci_dev)
1272     {                           /* bonded interface has no pci info */
1273       vlib_pci_addr_t pci_addr;
1274
1275       pci_addr.domain = dev_info.pci_dev->addr.domain;
1276       pci_addr.bus = dev_info.pci_dev->addr.bus;
1277       pci_addr.slot = dev_info.pci_dev->addr.devid;
1278       pci_addr.function = dev_info.pci_dev->addr.function;
1279
1280       p =
1281         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
1282     }
1283
1284   if (p)
1285     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
1286   else
1287     devconf = &dm->conf->default_devconf;
1288
1289   if (devconf->hqos_enabled == 0)
1290     {
1291       vlib_cli_output (vm, "HQoS disabled for this interface");
1292       return 0;
1293     }
1294
1295   n_subports_per_port = devconf->hqos.port.n_subports_per_port;
1296   n_pipes_per_subport = devconf->hqos.port.n_pipes_per_subport;
1297   tctbl_size = RTE_DIM (devconf->hqos.tc_table);
1298
1299   /* Validate packet field configuration: id, offset and mask */
1300   if (id >= 3)
1301     return clib_error_return (0, "invalid packet field id");
1302
1303   switch (id)
1304     {
1305     case 0:
1306       if (dpdk_hqos_validate_mask (mask, n_subports_per_port) != 0)
1307         return clib_error_return (0, "invalid subport ID mask "
1308                                   "(n_subports_per_port = %u)",
1309                                   n_subports_per_port);
1310       break;
1311     case 1:
1312       if (dpdk_hqos_validate_mask (mask, n_pipes_per_subport) != 0)
1313         return clib_error_return (0, "invalid pipe ID mask "
1314                                   "(n_pipes_per_subport = %u)",
1315                                   n_pipes_per_subport);
1316       break;
1317     case 2:
1318     default:
1319       if (dpdk_hqos_validate_mask (mask, tctbl_size) != 0)
1320         return clib_error_return (0, "invalid TC table index mask "
1321                                   "(TC table size = %u)", tctbl_size);
1322     }
1323
1324   /* Propagate packet field configuration to all workers */
1325   for (i = 0; i < worker_thread_count; i++)
1326     switch (id)
1327       {
1328       case 0:
1329         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabpos = offset;
1330         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabmask = mask;
1331         break;
1332       case 1:
1333         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabpos = offset;
1334         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabmask = mask;
1335         break;
1336       case 2:
1337       default:
1338         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabpos = offset;
1339         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabmask = mask;
1340       }
1341
1342   return 0;
1343 }
1344
1345 /* *INDENT-OFF* */
1346 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pktfield, static) = {
1347   .path = "set dpdk interface hqos pktfield",
1348   .short_help = "set dpdk interface hqos pktfield <if-name> id <n> offset <n> "
1349                  "mask <n>",
1350   .function = set_dpdk_if_hqos_pktfield,
1351 };
1352 /* *INDENT-ON* */
1353
1354 static clib_error_t *
1355 show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input,
1356                    vlib_cli_command_t * cmd)
1357 {
1358   unformat_input_t _line_input, *line_input = &_line_input;
1359   vlib_thread_main_t *tm = vlib_get_thread_main ();
1360   dpdk_main_t *dm = &dpdk_main;
1361   vnet_hw_interface_t *hw;
1362   dpdk_device_t *xd;
1363   dpdk_device_config_hqos_t *cfg;
1364   dpdk_device_hqos_per_hqos_thread_t *ht;
1365   dpdk_device_hqos_per_worker_thread_t *wk;
1366   u32 *tctbl;
1367   u32 hw_if_index = (u32) ~ 0;
1368   u32 profile_id, i;
1369   struct rte_eth_dev_info dev_info;
1370   dpdk_device_config_t *devconf = 0;
1371   vlib_thread_registration_t *tr;
1372   uword *p = 0;
1373
1374   if (!unformat_user (input, unformat_line_input, line_input))
1375     return 0;
1376
1377   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1378     {
1379       if (unformat
1380           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1381            &hw_if_index))
1382         ;
1383       else
1384         return clib_error_return (0, "parse error: '%U'",
1385                                   format_unformat_error, line_input);
1386     }
1387
1388   unformat_free (line_input);
1389
1390   if (hw_if_index == (u32) ~ 0)
1391     return clib_error_return (0, "please specify interface name!!");
1392
1393   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1394   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1395
1396   rte_eth_dev_info_get (xd->device_index, &dev_info);
1397   if (dev_info.pci_dev)
1398     {                           /* bonded interface has no pci info */
1399       vlib_pci_addr_t pci_addr;
1400
1401       pci_addr.domain = dev_info.pci_dev->addr.domain;
1402       pci_addr.bus = dev_info.pci_dev->addr.bus;
1403       pci_addr.slot = dev_info.pci_dev->addr.devid;
1404       pci_addr.function = dev_info.pci_dev->addr.function;
1405
1406       p =
1407         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
1408     }
1409
1410   if (p)
1411     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
1412   else
1413     devconf = &dm->conf->default_devconf;
1414
1415   if (devconf->hqos_enabled == 0)
1416     {
1417       vlib_cli_output (vm, "HQoS disabled for this interface");
1418       return 0;
1419     }
1420
1421   /* Detect the set of worker threads */
1422   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1423   tr = (vlib_thread_registration_t *) p[0];
1424
1425   cfg = &devconf->hqos;
1426   ht = xd->hqos_ht;
1427   wk = &xd->hqos_wt[tr->first_index];
1428   tctbl = wk->hqos_tc_table;
1429
1430   vlib_cli_output (vm, " Thread:");
1431   vlib_cli_output (vm, "   Input SWQ size = %u packets", cfg->swq_size);
1432   vlib_cli_output (vm, "   Enqueue burst size = %u packets",
1433                    ht->hqos_burst_enq);
1434   vlib_cli_output (vm, "   Dequeue burst size = %u packets",
1435                    ht->hqos_burst_deq);
1436
1437   vlib_cli_output (vm,
1438                    "   Packet field 0: slab position = %4u, slab bitmask = 0x%016llx",
1439                    wk->hqos_field0_slabpos, wk->hqos_field0_slabmask);
1440   vlib_cli_output (vm,
1441                    "   Packet field 1: slab position = %4u, slab bitmask = 0x%016llx",
1442                    wk->hqos_field1_slabpos, wk->hqos_field1_slabmask);
1443   vlib_cli_output (vm,
1444                    "   Packet field 2: slab position = %4u, slab bitmask = 0x%016llx",
1445                    wk->hqos_field2_slabpos, wk->hqos_field2_slabmask);
1446   vlib_cli_output (vm, "   Packet field 2 translation table:");
1447   vlib_cli_output (vm, "     [ 0 .. 15]: "
1448                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1449                    tctbl[0], tctbl[1], tctbl[2], tctbl[3],
1450                    tctbl[4], tctbl[5], tctbl[6], tctbl[7],
1451                    tctbl[8], tctbl[9], tctbl[10], tctbl[11],
1452                    tctbl[12], tctbl[13], tctbl[14], tctbl[15]);
1453   vlib_cli_output (vm, "     [16 .. 31]: "
1454                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1455                    tctbl[16], tctbl[17], tctbl[18], tctbl[19],
1456                    tctbl[20], tctbl[21], tctbl[22], tctbl[23],
1457                    tctbl[24], tctbl[25], tctbl[26], tctbl[27],
1458                    tctbl[28], tctbl[29], tctbl[30], tctbl[31]);
1459   vlib_cli_output (vm, "     [32 .. 47]: "
1460                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1461                    tctbl[32], tctbl[33], tctbl[34], tctbl[35],
1462                    tctbl[36], tctbl[37], tctbl[38], tctbl[39],
1463                    tctbl[40], tctbl[41], tctbl[42], tctbl[43],
1464                    tctbl[44], tctbl[45], tctbl[46], tctbl[47]);
1465   vlib_cli_output (vm, "     [48 .. 63]: "
1466                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1467                    tctbl[48], tctbl[49], tctbl[50], tctbl[51],
1468                    tctbl[52], tctbl[53], tctbl[54], tctbl[55],
1469                    tctbl[56], tctbl[57], tctbl[58], tctbl[59],
1470                    tctbl[60], tctbl[61], tctbl[62], tctbl[63]);
1471
1472   vlib_cli_output (vm, " Port:");
1473   vlib_cli_output (vm, "   Rate = %u bytes/second", cfg->port.rate);
1474   vlib_cli_output (vm, "   MTU = %u bytes", cfg->port.mtu);
1475   vlib_cli_output (vm, "   Frame overhead = %u bytes",
1476                    cfg->port.frame_overhead);
1477   vlib_cli_output (vm, "   Number of subports = %u",
1478                    cfg->port.n_subports_per_port);
1479   vlib_cli_output (vm, "   Number of pipes per subport = %u",
1480                    cfg->port.n_pipes_per_subport);
1481   vlib_cli_output (vm,
1482                    "   Packet queue size: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u packets",
1483                    cfg->port.qsize[0], cfg->port.qsize[1], cfg->port.qsize[2],
1484                    cfg->port.qsize[3]);
1485   vlib_cli_output (vm, "   Number of pipe profiles = %u",
1486                    cfg->port.n_pipe_profiles);
1487
1488   for (profile_id = 0; profile_id < vec_len (cfg->pipe); profile_id++)
1489     {
1490       vlib_cli_output (vm, " Pipe profile %u:", profile_id);
1491       vlib_cli_output (vm, "   Rate = %u bytes/second",
1492                        cfg->pipe[profile_id].tb_rate);
1493       vlib_cli_output (vm, "   Token bucket size = %u bytes",
1494                        cfg->pipe[profile_id].tb_size);
1495       vlib_cli_output (vm,
1496                        "   Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second",
1497                        cfg->pipe[profile_id].tc_rate[0],
1498                        cfg->pipe[profile_id].tc_rate[1],
1499                        cfg->pipe[profile_id].tc_rate[2],
1500                        cfg->pipe[profile_id].tc_rate[3]);
1501       vlib_cli_output (vm, "   TC period = %u milliseconds",
1502                        cfg->pipe[profile_id].tc_period);
1503 #ifdef RTE_SCHED_SUBPORT_TC_OV
1504       vlib_cli_output (vm, "   TC3 oversubscription_weight = %u",
1505                        cfg->pipe[profile_id].tc_ov_weight);
1506 #endif
1507
1508       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1509         {
1510           vlib_cli_output (vm,
1511                            "   TC%u WRR weights: Q0 = %u, Q1 = %u, Q2 = %u, Q3 = %u",
1512                            i, cfg->pipe[profile_id].wrr_weights[i * 4],
1513                            cfg->pipe[profile_id].wrr_weights[i * 4 + 1],
1514                            cfg->pipe[profile_id].wrr_weights[i * 4 + 2],
1515                            cfg->pipe[profile_id].wrr_weights[i * 4 + 3]);
1516         }
1517     }
1518
1519 #ifdef RTE_SCHED_RED
1520   vlib_cli_output (vm, " Weighted Random Early Detection (WRED):");
1521   for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1522     {
1523       vlib_cli_output (vm, "   TC%u min: G = %u, Y = %u, R = %u", i,
1524                        cfg->port.red_params[i][e_RTE_METER_GREEN].min_th,
1525                        cfg->port.red_params[i][e_RTE_METER_YELLOW].min_th,
1526                        cfg->port.red_params[i][e_RTE_METER_RED].min_th);
1527
1528       vlib_cli_output (vm, "   TC%u max: G = %u, Y = %u, R = %u", i,
1529                        cfg->port.red_params[i][e_RTE_METER_GREEN].max_th,
1530                        cfg->port.red_params[i][e_RTE_METER_YELLOW].max_th,
1531                        cfg->port.red_params[i][e_RTE_METER_RED].max_th);
1532
1533       vlib_cli_output (vm,
1534                        "   TC%u inverted probability: G = %u, Y = %u, R = %u",
1535                        i, cfg->port.red_params[i][e_RTE_METER_GREEN].maxp_inv,
1536                        cfg->port.red_params[i][e_RTE_METER_YELLOW].maxp_inv,
1537                        cfg->port.red_params[i][e_RTE_METER_RED].maxp_inv);
1538
1539       vlib_cli_output (vm, "   TC%u weight: R = %u, Y = %u, R = %u", i,
1540                        cfg->port.red_params[i][e_RTE_METER_GREEN].wq_log2,
1541                        cfg->port.red_params[i][e_RTE_METER_YELLOW].wq_log2,
1542                        cfg->port.red_params[i][e_RTE_METER_RED].wq_log2);
1543     }
1544 #endif
1545
1546   return 0;
1547 }
1548
1549 /* *INDENT-OFF* */
1550 VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos, static) = {
1551   .path = "show dpdk interface hqos",
1552   .short_help = "show dpdk interface hqos <if-name>",
1553   .function = show_dpdk_if_hqos,
1554 };
1555 /* *INDENT-ON* */
1556
1557 clib_error_t *
1558 dpdk_cli_init (vlib_main_t * vm)
1559 {
1560   return 0;
1561 }
1562
1563 VLIB_INIT_FUNCTION (dpdk_cli_init);
1564
1565 /*
1566  * fd.io coding-style-patch-verification: ON
1567  *
1568  * Local Variables:
1569  * eval: (c-set-style "gnu")
1570  * End:
1571  */