1 /* 2 * q_mqprio.c MQ prio qdisc 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Author: John Fastabend, <john.r.fastabend (at) intel.com> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <syslog.h> 16 #include <fcntl.h> 17 #include <sys/socket.h> 18 #include <netinet/in.h> 19 #include <arpa/inet.h> 20 #include <string.h> 21 22 #include "utils.h" 23 #include "tc_util.h" 24 25 static void explain(void) 26 { 27 fprintf(stderr, "Usage: ... mqprio [num_tc NUMBER] [map P0 P1 ...]\n"); 28 fprintf(stderr, " [queues count1@offset1 count2@offset2 ...] "); 29 fprintf(stderr, "[hw 1|0]\n"); 30 } 31 32 static int mqprio_parse_opt(struct qdisc_util *qu, int argc, 33 char **argv, struct nlmsghdr *n) 34 { 35 int idx; 36 struct tc_mqprio_qopt opt = { 37 .num_tc = 8, 38 .prio_tc_map = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 1, 3, 3, 3, 3 }, 39 .hw = 1, 40 .count = { }, 41 .offset = { }, 42 }; 43 44 while (argc > 0) { 45 idx = 0; 46 if (strcmp(*argv, "num_tc") == 0) { 47 NEXT_ARG(); 48 if (get_u8(&opt.num_tc, *argv, 10)) { 49 fprintf(stderr, "Illegal \"num_tc\"\n"); 50 return -1; 51 } 52 } else if (strcmp(*argv, "map") == 0) { 53 while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) { 54 NEXT_ARG(); 55 if (get_u8(&opt.prio_tc_map[idx], *argv, 10)) { 56 PREV_ARG(); 57 break; 58 } 59 idx++; 60 } 61 for ( ; idx < TC_QOPT_MAX_QUEUE; idx++) 62 opt.prio_tc_map[idx] = 0; 63 } else if (strcmp(*argv, "queues") == 0) { 64 char *tmp, *tok; 65 66 while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) { 67 NEXT_ARG(); 68 69 tmp = strdup(*argv); 70 if (!tmp) 71 break; 72 73 tok = strtok(tmp, "@"); 74 if (get_u16(&opt.count[idx], tok, 10)) { 75 free(tmp); 76 PREV_ARG(); 77 break; 78 } 79 tok = strtok(NULL, "@"); 80 if (get_u16(&opt.offset[idx], tok, 10)) { 81 free(tmp); 82 PREV_ARG(); 83 break; 84 } 85 free(tmp); 86 idx++; 87 } 88 } else if (strcmp(*argv, "hw") == 0) { 89 NEXT_ARG(); 90 if (get_u8(&opt.hw, *argv, 10)) { 91 fprintf(stderr, "Illegal \"hw\"\n"); 92 return -1; 93 } 94 idx++; 95 } else if (strcmp(*argv, "help") == 0) { 96 explain(); 97 return -1; 98 } else { 99 fprintf(stderr, "Unknown argument\n"); 100 return -1; 101 } 102 argc--; argv++; 103 } 104 105 addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); 106 return 0; 107 } 108 109 static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 110 { 111 int i; 112 struct tc_mqprio_qopt *qopt; 113 114 if (opt == NULL) 115 return 0; 116 117 qopt = RTA_DATA(opt); 118 119 fprintf(f, " tc %u map ", qopt->num_tc); 120 for (i = 0; i <= TC_PRIO_MAX; i++) 121 fprintf(f, "%u ", qopt->prio_tc_map[i]); 122 fprintf(f, "\n queues:"); 123 for (i = 0; i < qopt->num_tc; i++) 124 fprintf(f, "(%u:%u) ", qopt->offset[i], 125 qopt->offset[i] + qopt->count[i] - 1); 126 return 0; 127 } 128 129 struct qdisc_util mqprio_qdisc_util = { 130 .id = "mqprio", 131 .parse_qopt = mqprio_parse_opt, 132 .print_qopt = mqprio_print_opt, 133 }; 134