Fix build break in 64bit architectures
[platform/upstream/iproute2.git] / tc / q_mqprio.c
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@intel.com>
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <string.h>
20
21 #include "utils.h"
22 #include "tc_util.h"
23
24 static void explain(void)
25 {
26         fprintf(stderr,
27                 "Usage: ... mqprio      [num_tc NUMBER] [map P0 P1 ...]\n"
28                 "                       [queues count1@offset1 count2@offset2 ...] "
29                 "[hw 1|0]\n"
30                 "                       [mode dcb|channel]\n"
31                 "                       [shaper bw_rlimit SHAPER_PARAMS]\n"
32                 "Where: SHAPER_PARAMS := { min_rate MIN_RATE1 MIN_RATE2 ...|\n"
33                 "                         max_rate MAX_RATE1 MAX_RATE2 ... }\n");
34 }
35
36 static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
37                             char **argv, struct nlmsghdr *n, const char *dev)
38 {
39         int idx;
40         struct tc_mqprio_qopt opt = {
41                 .num_tc = 8,
42                 .prio_tc_map = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 1, 3, 3, 3, 3 },
43                 .hw = 1,
44                 .count = { },
45                 .offset = { },
46         };
47         __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
48         __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
49         __u16 shaper = TC_MQPRIO_SHAPER_DCB;
50         __u16 mode = TC_MQPRIO_MODE_DCB;
51         struct rtattr *tail;
52         __u32 flags = 0;
53
54         while (argc > 0) {
55                 idx = 0;
56                 if (strcmp(*argv, "num_tc") == 0) {
57                         NEXT_ARG();
58                         if (get_u8(&opt.num_tc, *argv, 10)) {
59                                 fprintf(stderr, "Illegal \"num_tc\"\n");
60                                 return -1;
61                         }
62                 } else if (strcmp(*argv, "map") == 0) {
63                         while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
64                                 NEXT_ARG();
65                                 if (get_u8(&opt.prio_tc_map[idx], *argv, 10)) {
66                                         PREV_ARG();
67                                         break;
68                                 }
69                                 idx++;
70                         }
71                         for ( ; idx < TC_QOPT_MAX_QUEUE; idx++)
72                                 opt.prio_tc_map[idx] = 0;
73                 } else if (strcmp(*argv, "queues") == 0) {
74                         char *tmp, *tok;
75
76                         while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
77                                 NEXT_ARG();
78
79                                 tmp = strdup(*argv);
80                                 if (!tmp)
81                                         break;
82
83                                 tok = strtok(tmp, "@");
84                                 if (get_u16(&opt.count[idx], tok, 10)) {
85                                         free(tmp);
86                                         PREV_ARG();
87                                         break;
88                                 }
89                                 tok = strtok(NULL, "@");
90                                 if (get_u16(&opt.offset[idx], tok, 10)) {
91                                         free(tmp);
92                                         PREV_ARG();
93                                         break;
94                                 }
95                                 free(tmp);
96                                 idx++;
97                         }
98                 } else if (strcmp(*argv, "hw") == 0) {
99                         NEXT_ARG();
100                         if (get_u8(&opt.hw, *argv, 10)) {
101                                 fprintf(stderr, "Illegal \"hw\"\n");
102                                 return -1;
103                         }
104                         idx++;
105                 } else if (opt.hw && strcmp(*argv, "mode") == 0) {
106                         NEXT_ARG();
107                         if (matches(*argv, "dcb") == 0) {
108                                 mode = TC_MQPRIO_MODE_DCB;
109                         } else if (matches(*argv, "channel") == 0) {
110                                 mode = TC_MQPRIO_MODE_CHANNEL;
111                         }  else {
112                                 fprintf(stderr, "Illegal mode (%s)\n",
113                                         *argv);
114                                 return -1;
115                         }
116                         if (mode != TC_MQPRIO_MODE_DCB)
117                                 flags |= TC_MQPRIO_F_MODE;
118                         idx++;
119                 } else if (opt.hw && strcmp(*argv, "shaper") == 0) {
120                         NEXT_ARG();
121                         if (matches(*argv, "dcb") == 0) {
122                                 shaper = TC_MQPRIO_SHAPER_DCB;
123                         } else if (matches(*argv, "bw_rlimit") == 0) {
124                                 shaper = TC_MQPRIO_SHAPER_BW_RATE;
125                                 if (!NEXT_ARG_OK()) {
126                                         fprintf(stderr, "Incomplete shaper arguments\n");
127                                         return -1;
128                                 }
129                         }  else {
130                                 fprintf(stderr, "Illegal shaper (%s)\n",
131                                         *argv);
132                                 return -1;
133                         }
134                         if (shaper != TC_MQPRIO_SHAPER_DCB)
135                                 flags |= TC_MQPRIO_F_SHAPER;
136                         idx++;
137                 } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
138                            strcmp(*argv, "min_rate") == 0) {
139                         while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
140                                 NEXT_ARG();
141                                 if (get_rate64(&min_rate64[idx], *argv)) {
142                                         PREV_ARG();
143                                         break;
144                                 }
145                                 idx++;
146                         }
147                         if (idx < opt.num_tc && !NEXT_ARG_OK()) {
148                                 fprintf(stderr, "Incomplete arguments, min_rate values expected\n");
149                                 return -1;
150                         }
151                         flags |= TC_MQPRIO_F_MIN_RATE;
152                 } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
153                            strcmp(*argv, "max_rate") == 0) {
154                         while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
155                                 NEXT_ARG();
156                                 if (get_rate64(&max_rate64[idx], *argv)) {
157                                         PREV_ARG();
158                                         break;
159                                 }
160                                 idx++;
161                         }
162                         if (idx < opt.num_tc && !NEXT_ARG_OK()) {
163                                 fprintf(stderr, "Incomplete arguments, max_rate values expected\n");
164                                 return -1;
165                         }
166                         flags |= TC_MQPRIO_F_MAX_RATE;
167                 } else if (strcmp(*argv, "help") == 0) {
168                         explain();
169                         return -1;
170                 } else {
171                         invarg("unknown argument", *argv);
172                 }
173                 argc--; argv++;
174         }
175
176         tail = NLMSG_TAIL(n);
177         addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
178
179         if (flags & TC_MQPRIO_F_MODE)
180                 addattr_l(n, 1024, TCA_MQPRIO_MODE,
181                           &mode, sizeof(mode));
182         if (flags & TC_MQPRIO_F_SHAPER)
183                 addattr_l(n, 1024, TCA_MQPRIO_SHAPER,
184                           &shaper, sizeof(shaper));
185
186         if (flags & TC_MQPRIO_F_MIN_RATE) {
187                 struct rtattr *start;
188
189                 start = addattr_nest(n, 1024,
190                                      TCA_MQPRIO_MIN_RATE64 | NLA_F_NESTED);
191
192                 for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
193                         addattr_l(n, 1024, TCA_MQPRIO_MIN_RATE64,
194                                   &min_rate64[idx], sizeof(min_rate64[idx]));
195
196                 addattr_nest_end(n, start);
197         }
198
199         if (flags & TC_MQPRIO_F_MAX_RATE) {
200                 struct rtattr *start;
201
202                 start = addattr_nest(n, 1024,
203                                      TCA_MQPRIO_MAX_RATE64 | NLA_F_NESTED);
204
205                 for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
206                         addattr_l(n, 1024, TCA_MQPRIO_MAX_RATE64,
207                                   &max_rate64[idx], sizeof(max_rate64[idx]));
208
209                 addattr_nest_end(n, start);
210         }
211
212         tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
213
214         return 0;
215 }
216
217 static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
218 {
219         int i;
220         struct tc_mqprio_qopt *qopt;
221         __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
222         __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
223         int len;
224
225         SPRINT_BUF(b1);
226
227         if (opt == NULL)
228                 return 0;
229
230         len = RTA_PAYLOAD(opt) - RTA_ALIGN(sizeof(*qopt));
231         if (len < 0) {
232                 fprintf(stderr, "options size error\n");
233                 return -1;
234         }
235
236         qopt = RTA_DATA(opt);
237
238         fprintf(f, " tc %u map ", qopt->num_tc);
239         for (i = 0; i <= TC_PRIO_MAX; i++)
240                 fprintf(f, "%u ", qopt->prio_tc_map[i]);
241         fprintf(f, "\n             queues:");
242         for (i = 0; i < qopt->num_tc; i++)
243                 fprintf(f, "(%u:%u) ", qopt->offset[i],
244                         qopt->offset[i] + qopt->count[i] - 1);
245
246         if (len > 0) {
247                 struct rtattr *tb[TCA_MQPRIO_MAX + 1];
248
249                 parse_rtattr(tb, TCA_MQPRIO_MAX,
250                              RTA_DATA(opt) + RTA_ALIGN(sizeof(*qopt)),
251                              len);
252
253                 if (tb[TCA_MQPRIO_MODE]) {
254                         __u16 *mode = RTA_DATA(tb[TCA_MQPRIO_MODE]);
255
256                         if (*mode == TC_MQPRIO_MODE_CHANNEL)
257                                 fprintf(f, "\n             mode:channel");
258                 } else {
259                         fprintf(f, "\n             mode:dcb");
260                 }
261
262                 if (tb[TCA_MQPRIO_SHAPER]) {
263                         __u16 *shaper = RTA_DATA(tb[TCA_MQPRIO_SHAPER]);
264
265                         if (*shaper == TC_MQPRIO_SHAPER_BW_RATE)
266                                 fprintf(f, "\n             shaper:bw_rlimit");
267                 } else {
268                         fprintf(f, "\n             shaper:dcb");
269                 }
270
271                 if (tb[TCA_MQPRIO_MIN_RATE64]) {
272                         struct rtattr *r;
273                         int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MIN_RATE64]);
274                         __u64 *min = min_rate64;
275
276                         for (r = RTA_DATA(tb[TCA_MQPRIO_MIN_RATE64]);
277                              RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
278                                 if (r->rta_type != TCA_MQPRIO_MIN_RATE64)
279                                         return -1;
280                                 *(min++) = rta_getattr_u64(r);
281                         }
282                         fprintf(f, "    min_rate:");
283                         for (i = 0; i < qopt->num_tc; i++)
284                                 fprintf(f, "%s ", sprint_rate(min_rate64[i], b1));
285                 }
286
287                 if (tb[TCA_MQPRIO_MAX_RATE64]) {
288                         struct rtattr *r;
289                         int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MAX_RATE64]);
290                         __u64 *max = max_rate64;
291
292                         for (r = RTA_DATA(tb[TCA_MQPRIO_MAX_RATE64]);
293                              RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
294                                 if (r->rta_type != TCA_MQPRIO_MAX_RATE64)
295                                         return -1;
296                                 *(max++) = rta_getattr_u64(r);
297                         }
298                         fprintf(f, "    max_rate:");
299                         for (i = 0; i < qopt->num_tc; i++)
300                                 fprintf(f, "%s ", sprint_rate(max_rate64[i], b1));
301                 }
302         }
303         return 0;
304 }
305
306 struct qdisc_util mqprio_qdisc_util = {
307         .id             = "mqprio",
308         .parse_qopt     = mqprio_parse_opt,
309         .print_qopt     = mqprio_print_opt,
310 };