]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/f_u32.c
devlink: Add support for resource/dpipe relation
[mirror_iproute2.git] / tc / f_u32.c
CommitLineData
aba5acdf
SH
1/*
2 * q_u32.c U32 filter.
3 *
4 * This program is free software; you can u32istribute 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 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6f0ba88b 10 * Match mark added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> [5 nov 2004]
aba5acdf
SH
11 *
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
aba5acdf
SH
17#include <fcntl.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <arpa/inet.h>
21#include <string.h>
2373fde9 22#include <linux/if.h>
1750abe2 23#include <linux/if_ether.h>
aba5acdf
SH
24
25#include "utils.h"
26#include "tc_util.h"
27
44dcfe82
SH
28extern int show_pretty;
29
aba5acdf
SH
30static void explain(void)
31{
62281205
SH
32 fprintf(stderr,
33 "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"
34 " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"
35 " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"
fb12cea8 36 " [ sample SAMPLE ] [skip_hw | skip_sw]\n"
62281205
SH
37 "or u32 divisor DIVISOR\n"
38 "\n"
39 "Where: SELECTOR := SAMPLE SAMPLE ...\n"
40 " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n"
41 " SAMPLE_ARGS [ divisor DIVISOR ]\n"
42 " FILTERID := X:Y:Z\n"
43 "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
aba5acdf
SH
44}
45
d1f28cf1 46static int get_u32_handle(__u32 *handle, const char *str)
aba5acdf 47{
dd0c8d19 48 __u32 htid = 0, hash = 0, nodeid = 0;
aba5acdf
SH
49 char *tmp = strchr(str, ':');
50
51 if (tmp == NULL) {
52 if (memcmp("0x", str, 2) == 0)
53 return get_u32(handle, str, 16);
54 return -1;
55 }
56 htid = strtoul(str, &tmp, 16);
57 if (tmp == str && *str != ':' && *str != 0)
58 return -1;
dd0c8d19 59 if (htid >= 0x1000)
aba5acdf
SH
60 return -1;
61 if (*tmp) {
40eb737e 62 str = tmp + 1;
aba5acdf
SH
63 hash = strtoul(str, &tmp, 16);
64 if (tmp == str && *str != ':' && *str != 0)
65 return -1;
dd0c8d19 66 if (hash >= 0x100)
aba5acdf
SH
67 return -1;
68 if (*tmp) {
40eb737e 69 str = tmp + 1;
aba5acdf
SH
70 nodeid = strtoul(str, &tmp, 16);
71 if (tmp == str && *str != 0)
72 return -1;
dd0c8d19 73 if (nodeid >= 0x1000)
aba5acdf
SH
74 return -1;
75 }
76 }
77 *handle = (htid<<20)|(hash<<12)|nodeid;
78 return 0;
79}
80
725f2a87 81static char *sprint_u32_handle(__u32 handle, char *buf)
aba5acdf
SH
82{
83 int bsize = SPRINT_BSIZE-1;
84 __u32 htid = TC_U32_HTID(handle);
85 __u32 hash = TC_U32_HASH(handle);
86 __u32 nodeid = TC_U32_NODE(handle);
87 char *b = buf;
88
89 if (handle == 0) {
90 snprintf(b, bsize, "none");
91 return b;
92 }
93 if (htid) {
94 int l = snprintf(b, bsize, "%x:", htid>>20);
32a121cb 95
aba5acdf
SH
96 bsize -= l;
97 b += l;
98 }
99 if (nodeid|hash) {
100 if (hash) {
101 int l = snprintf(b, bsize, "%x", hash);
32a121cb 102
aba5acdf
SH
103 bsize -= l;
104 b += l;
105 }
106 if (nodeid) {
107 int l = snprintf(b, bsize, ":%x", nodeid);
32a121cb 108
aba5acdf
SH
109 bsize -= l;
110 b += l;
111 }
112 }
113 if (show_raw)
114 snprintf(b, bsize, "[%08x] ", handle);
115 return buf;
116}
117
e62077d0
SH
118static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
119 int off, int offmask)
aba5acdf
SH
120{
121 int i;
122 int hwm = sel->nkeys;
123
124 key &= mask;
125
dd0c8d19 126 for (i = 0; i < hwm; i++) {
aba5acdf 127 if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
40eb737e 128 __u32 intersect = mask & sel->keys[i].mask;
aba5acdf 129
40eb737e 130 if ((key ^ sel->keys[i].val) & intersect)
aba5acdf
SH
131 return -1;
132 sel->keys[i].val |= key;
133 sel->keys[i].mask |= mask;
134 return 0;
135 }
136 }
137
138 if (hwm >= 128)
139 return -1;
140 if (off % 4)
141 return -1;
142 sel->keys[hwm].val = key;
143 sel->keys[hwm].mask = mask;
144 sel->keys[hwm].off = off;
145 sel->keys[hwm].offmask = offmask;
146 sel->nkeys++;
147 return 0;
148}
149
e62077d0
SH
150static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
151 int off, int offmask)
aba5acdf
SH
152{
153 key = htonl(key);
154 mask = htonl(mask);
155 return pack_key(sel, key, mask, off, offmask);
156}
157
e62077d0
SH
158static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
159 int off, int offmask)
aba5acdf
SH
160{
161 if (key > 0xFFFF || mask > 0xFFFF)
162 return -1;
163
164 if ((off & 3) == 0) {
165 key <<= 16;
166 mask <<= 16;
167 }
168 off &= ~3;
169 key = htonl(key);
170 mask = htonl(mask);
171
172 return pack_key(sel, key, mask, off, offmask);
173}
174
82e6efe2
JHS
175static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off,
176 int offmask)
aba5acdf
SH
177{
178 if (key > 0xFF || mask > 0xFF)
179 return -1;
180
181 if ((off & 3) == 0) {
182 key <<= 24;
183 mask <<= 24;
184 } else if ((off & 3) == 1) {
185 key <<= 16;
186 mask <<= 16;
187 } else if ((off & 3) == 2) {
188 key <<= 8;
189 mask <<= 8;
190 }
191 off &= ~3;
192 key = htonl(key);
193 mask = htonl(mask);
194
195 return pack_key(sel, key, mask, off, offmask);
196}
197
198
d1f28cf1 199static int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
aba5acdf
SH
200{
201 int argc = *argc_p;
202 char **argv = *argv_p;
203 char *p = *argv;
204
205 if (argc <= 0)
206 return -1;
207
208 if (strlen(p) > strlen("nexthdr+") &&
209 memcmp(p, "nexthdr+", strlen("nexthdr+")) == 0) {
210 *offmask = -1;
211 p += strlen("nexthdr+");
212 } else if (matches(*argv, "nexthdr+") == 0) {
213 NEXT_ARG();
214 *offmask = -1;
215 p = *argv;
216 }
217
218 if (get_integer(off, p, 0))
219 return -1;
220 argc--; argv++;
221
222 *argc_p = argc;
223 *argv_p = argv;
224 return 0;
225}
226
227
e62077d0
SH
228static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
229 int off, int offmask)
aba5acdf
SH
230{
231 int res = -1;
232 int argc = *argc_p;
233 char **argv = *argv_p;
234 __u32 key;
235 __u32 mask;
236
237 if (argc < 2)
238 return -1;
239
240 if (get_u32(&key, *argv, 0))
241 return -1;
242 argc--; argv++;
243
244 if (get_u32(&mask, *argv, 16))
245 return -1;
246 argc--; argv++;
247
248 if (argc > 0 && strcmp(argv[0], "at") == 0) {
249 NEXT_ARG();
250 if (parse_at(&argc, &argv, &off, &offmask))
251 return -1;
252 }
253
254 res = pack_key32(sel, key, mask, off, offmask);
255 *argc_p = argc;
256 *argv_p = argv;
257 return res;
258}
259
e62077d0
SH
260static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
261 int off, int offmask)
aba5acdf
SH
262{
263 int res = -1;
264 int argc = *argc_p;
265 char **argv = *argv_p;
266 __u32 key;
267 __u32 mask;
268
269 if (argc < 2)
270 return -1;
271
272 if (get_u32(&key, *argv, 0))
273 return -1;
274 argc--; argv++;
275
276 if (get_u32(&mask, *argv, 16))
277 return -1;
278 argc--; argv++;
279
280 if (argc > 0 && strcmp(argv[0], "at") == 0) {
281 NEXT_ARG();
282 if (parse_at(&argc, &argv, &off, &offmask))
283 return -1;
284 }
285 res = pack_key16(sel, key, mask, off, offmask);
286 *argc_p = argc;
287 *argv_p = argv;
288 return res;
289}
290
e62077d0
SH
291static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
292 int off, int offmask)
aba5acdf
SH
293{
294 int res = -1;
295 int argc = *argc_p;
296 char **argv = *argv_p;
297 __u32 key;
298 __u32 mask;
299
300 if (argc < 2)
301 return -1;
302
303 if (get_u32(&key, *argv, 0))
304 return -1;
305 argc--; argv++;
306
307 if (get_u32(&mask, *argv, 16))
308 return -1;
309 argc--; argv++;
310
311 if (key > 0xFF || mask > 0xFF)
312 return -1;
313
314 if (argc > 0 && strcmp(argv[0], "at") == 0) {
315 NEXT_ARG();
316 if (parse_at(&argc, &argv, &off, &offmask))
317 return -1;
318 }
319
320 res = pack_key8(sel, key, mask, off, offmask);
321 *argc_p = argc;
322 *argv_p = argv;
323 return res;
324}
325
e62077d0
SH
326static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
327 int off)
aba5acdf
SH
328{
329 int res = -1;
330 int argc = *argc_p;
331 char **argv = *argv_p;
332 inet_prefix addr;
333 __u32 mask;
334 int offmask = 0;
335
336 if (argc < 1)
337 return -1;
338
339 if (get_prefix_1(&addr, *argv, AF_INET))
340 return -1;
341 argc--; argv++;
342
343 if (argc > 0 && strcmp(argv[0], "at") == 0) {
344 NEXT_ARG();
345 if (parse_at(&argc, &argv, &off, &offmask))
346 return -1;
347 }
348
349 mask = 0;
350 if (addr.bitlen)
40eb737e 351 mask = htonl(0xFFFFFFFF << (32 - addr.bitlen));
aba5acdf
SH
352 if (pack_key(sel, addr.data[0], mask, off, offmask) < 0)
353 return -1;
354 res = 0;
355
356 *argc_p = argc;
357 *argv_p = argv;
358 return res;
359}
360
e62077d0
SH
361static int parse_ip6_addr(int *argc_p, char ***argv_p,
362 struct tc_u32_sel *sel, int off)
aba5acdf
SH
363{
364 int res = -1;
365 int argc = *argc_p;
366 char **argv = *argv_p;
367 int plen = 128;
368 int i;
369 inet_prefix addr;
370 int offmask = 0;
371
372 if (argc < 1)
373 return -1;
374
375 if (get_prefix_1(&addr, *argv, AF_INET6))
376 return -1;
377 argc--; argv++;
378
379 if (argc > 0 && strcmp(argv[0], "at") == 0) {
380 NEXT_ARG();
381 if (parse_at(&argc, &argv, &off, &offmask))
382 return -1;
383 }
384
385 plen = addr.bitlen;
40eb737e 386 for (i = 0; i < plen; i += 32) {
73451259 387 if (i + 31 < plen) {
40eb737e
PS
388 res = pack_key(sel, addr.data[i / 32],
389 0xFFFFFFFF, off + 4 * (i / 32), offmask);
e62077d0 390 if (res < 0)
aba5acdf 391 return -1;
e62077d0 392 } else if (i < plen) {
40eb737e 393 __u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i)));
32a121cb 394
40eb737e
PS
395 res = pack_key(sel, addr.data[i / 32],
396 mask, off + 4 * (i / 32), offmask);
e62077d0 397 if (res < 0)
aba5acdf
SH
398 return -1;
399 }
400 }
401 res = 0;
402
403 *argc_p = argc;
404 *argv_p = argv;
405 return res;
406}
407
01564122
PL
408static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
409{
410 int res = -1;
411 int argc = *argc_p;
412 char **argv = *argv_p;
413 __u32 key;
414 __u32 mask;
415 int off = 0;
416 int offmask = 0;
417
418 if (argc < 2)
419 return -1;
420
421 if (get_u32(&key, *argv, 0))
422 return -1;
423 argc--; argv++;
424
425 if (get_u32(&mask, *argv, 16))
426 return -1;
427 argc--; argv++;
428
429 if (key > 0xFF || mask > 0xFF)
430 return -1;
431
432 key <<= 20;
433 mask <<= 20;
434 key = htonl(key);
435 mask = htonl(mask);
436
d7ac9ad4
SH
437 res = pack_key(sel, key, mask, off, offmask);
438 if (res < 0)
01564122
PL
439 return -1;
440
441 *argc_p = argc;
442 *argv_p = argv;
443 return 0;
444}
445
b4d41f41
SH
446static int parse_ether_addr(int *argc_p, char ***argv_p,
447 struct tc_u32_sel *sel, int off)
448{
449 int res = -1;
450 int argc = *argc_p;
451 char **argv = *argv_p;
452 __u8 addr[6];
453 int offmask = 0;
b4d41f41
SH
454 int i;
455
456 if (argc < 1)
457 return -1;
458
459 if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
460 addr + 0, addr + 1, addr + 2,
461 addr + 3, addr + 4, addr + 5) != 6) {
462 fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
463 *argv);
464 return -1;
465 }
466
467 argc--; argv++;
468 if (argc > 0 && strcmp(argv[0], "at") == 0) {
469 NEXT_ARG();
470 if (parse_at(&argc, &argv, &off, &offmask))
471 return -1;
472 }
473
e3d153c1
SH
474 for (i = 0; i < 6; i++) {
475 res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
b4d41f41
SH
476 if (res < 0)
477 return -1;
478 }
479
480 *argc_p = argc;
481 *argv_p = argv;
482 return res;
483}
484
aba5acdf
SH
485static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
486{
487 int res = -1;
488 int argc = *argc_p;
489 char **argv = *argv_p;
490
491 if (argc < 2)
492 return -1;
493
494 if (strcmp(*argv, "src") == 0) {
495 NEXT_ARG();
496 res = parse_ip_addr(&argc, &argv, sel, 12);
9fce67dd 497 } else if (strcmp(*argv, "dst") == 0) {
aba5acdf
SH
498 NEXT_ARG();
499 res = parse_ip_addr(&argc, &argv, sel, 16);
9fce67dd 500 } else if (strcmp(*argv, "tos") == 0 ||
40eb737e
PS
501 matches(*argv, "dsfield") == 0 ||
502 matches(*argv, "precedence") == 0) {
aba5acdf
SH
503 NEXT_ARG();
504 res = parse_u8(&argc, &argv, sel, 1, 0);
9fce67dd 505 } else if (strcmp(*argv, "ihl") == 0) {
aba5acdf
SH
506 NEXT_ARG();
507 res = parse_u8(&argc, &argv, sel, 0, 0);
9fce67dd 508 } else if (strcmp(*argv, "protocol") == 0) {
aba5acdf
SH
509 NEXT_ARG();
510 res = parse_u8(&argc, &argv, sel, 9, 0);
9fce67dd 511 } else if (strcmp(*argv, "nofrag") == 0) {
aba5acdf
SH
512 argc--; argv++;
513 res = pack_key16(sel, 0, 0x3FFF, 6, 0);
9fce67dd 514 } else if (strcmp(*argv, "firstfrag") == 0) {
aba5acdf 515 argc--; argv++;
690b11f4 516 res = pack_key16(sel, 0x2000, 0x3FFF, 6, 0);
9fce67dd 517 } else if (strcmp(*argv, "df") == 0) {
aba5acdf
SH
518 argc--; argv++;
519 res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
9fce67dd 520 } else if (strcmp(*argv, "mf") == 0) {
aba5acdf
SH
521 argc--; argv++;
522 res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
9fce67dd 523 } else if (strcmp(*argv, "dport") == 0) {
aba5acdf
SH
524 NEXT_ARG();
525 res = parse_u16(&argc, &argv, sel, 22, 0);
9fce67dd 526 } else if (strcmp(*argv, "sport") == 0) {
aba5acdf
SH
527 NEXT_ARG();
528 res = parse_u16(&argc, &argv, sel, 20, 0);
9fce67dd 529 } else if (strcmp(*argv, "icmp_type") == 0) {
aba5acdf
SH
530 NEXT_ARG();
531 res = parse_u8(&argc, &argv, sel, 20, 0);
9fce67dd 532 } else if (strcmp(*argv, "icmp_code") == 0) {
aba5acdf 533 NEXT_ARG();
1d62f99f 534 res = parse_u8(&argc, &argv, sel, 21, 0);
9fce67dd
SH
535 } else
536 return -1;
aba5acdf 537
aba5acdf
SH
538 *argc_p = argc;
539 *argv_p = argv;
540 return res;
541}
3d0b7439 542
aba5acdf
SH
543static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
544{
545 int res = -1;
546 int argc = *argc_p;
547 char **argv = *argv_p;
548
549 if (argc < 2)
550 return -1;
551
552 if (strcmp(*argv, "src") == 0) {
553 NEXT_ARG();
554 res = parse_ip6_addr(&argc, &argv, sel, 8);
9fce67dd 555 } else if (strcmp(*argv, "dst") == 0) {
aba5acdf
SH
556 NEXT_ARG();
557 res = parse_ip6_addr(&argc, &argv, sel, 24);
9fce67dd 558 } else if (strcmp(*argv, "priority") == 0) {
aba5acdf 559 NEXT_ARG();
01564122 560 res = parse_ip6_class(&argc, &argv, sel);
9fce67dd 561 } else if (strcmp(*argv, "protocol") == 0) {
aba5acdf
SH
562 NEXT_ARG();
563 res = parse_u8(&argc, &argv, sel, 6, 0);
9fce67dd 564 } else if (strcmp(*argv, "flowlabel") == 0) {
aba5acdf
SH
565 NEXT_ARG();
566 res = parse_u32(&argc, &argv, sel, 0, 0);
9fce67dd 567 } else if (strcmp(*argv, "dport") == 0) {
aba5acdf
SH
568 NEXT_ARG();
569 res = parse_u16(&argc, &argv, sel, 42, 0);
9fce67dd 570 } else if (strcmp(*argv, "sport") == 0) {
aba5acdf
SH
571 NEXT_ARG();
572 res = parse_u16(&argc, &argv, sel, 40, 0);
9fce67dd 573 } else if (strcmp(*argv, "icmp_type") == 0) {
aba5acdf
SH
574 NEXT_ARG();
575 res = parse_u8(&argc, &argv, sel, 40, 0);
9fce67dd 576 } else if (strcmp(*argv, "icmp_code") == 0) {
aba5acdf
SH
577 NEXT_ARG();
578 res = parse_u8(&argc, &argv, sel, 41, 1);
9fce67dd
SH
579 } else
580 return -1;
aba5acdf 581
aba5acdf
SH
582 *argc_p = argc;
583 *argv_p = argv;
584 return res;
585}
586
b4d41f41
SH
587static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
588{
589 int res = -1;
590 int argc = *argc_p;
591 char **argv = *argv_p;
592
593 if (argc < 2)
594 return -1;
595
596 if (strcmp(*argv, "src") == 0) {
597 NEXT_ARG();
598 res = parse_ether_addr(&argc, &argv, sel, -8);
599 } else if (strcmp(*argv, "dst") == 0) {
600 NEXT_ARG();
601 res = parse_ether_addr(&argc, &argv, sel, -14);
602 } else {
603 fprintf(stderr, "Unknown match: ether %s\n", *argv);
604 return -1;
605 }
606
607 *argc_p = argc;
608 *argv_p = argv;
609 return res;
610}
611
aba5acdf
SH
612#define parse_tcp parse_udp
613static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
614{
615 int res = -1;
616 int argc = *argc_p;
617 char **argv = *argv_p;
618
619 if (argc < 2)
620 return -1;
621
622 if (strcmp(*argv, "src") == 0) {
623 NEXT_ARG();
624 res = parse_u16(&argc, &argv, sel, 0, -1);
9fce67dd 625 } else if (strcmp(*argv, "dst") == 0) {
aba5acdf
SH
626 NEXT_ARG();
627 res = parse_u16(&argc, &argv, sel, 2, -1);
9fce67dd
SH
628 } else
629 return -1;
aba5acdf 630
aba5acdf
SH
631 *argc_p = argc;
632 *argv_p = argv;
633 return res;
634}
635
6b1ac654 636
aba5acdf
SH
637static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
638{
639 int res = -1;
640 int argc = *argc_p;
641 char **argv = *argv_p;
642
643 if (argc < 2)
644 return -1;
645
646 if (strcmp(*argv, "type") == 0) {
647 NEXT_ARG();
648 res = parse_u8(&argc, &argv, sel, 0, -1);
9fce67dd 649 } else if (strcmp(*argv, "code") == 0) {
aba5acdf
SH
650 NEXT_ARG();
651 res = parse_u8(&argc, &argv, sel, 1, -1);
9fce67dd
SH
652 } else
653 return -1;
aba5acdf 654
aba5acdf
SH
655 *argc_p = argc;
656 *argv_p = argv;
657 return res;
658}
659
6f0ba88b 660static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
661{
662 int res = -1;
663 int argc = *argc_p;
664 char **argv = *argv_p;
665 struct tc_u32_mark mark;
666
667 if (argc <= 1)
668 return -1;
669
670 if (get_u32(&mark.val, *argv, 0)) {
671 fprintf(stderr, "Illegal \"mark\" value\n");
672 return -1;
673 }
674 NEXT_ARG();
675
676 if (get_u32(&mark.mask, *argv, 0)) {
677 fprintf(stderr, "Illegal \"mark\" mask\n");
678 return -1;
679 }
680 NEXT_ARG();
681
682 if ((mark.val & mark.mask) != mark.val) {
683 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
684 return -1;
685 }
aba5acdf 686
6f0ba88b 687 addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
688 res = 0;
689
690 *argc_p = argc;
691 *argv_p = argv;
692 return res;
693}
aba5acdf 694
e62077d0
SH
695static int parse_selector(int *argc_p, char ***argv_p,
696 struct tc_u32_sel *sel, struct nlmsghdr *n)
aba5acdf
SH
697{
698 int argc = *argc_p;
699 char **argv = *argv_p;
700 int res = -1;
701
702 if (argc <= 0)
703 return -1;
704
705 if (matches(*argv, "u32") == 0) {
706 NEXT_ARG();
707 res = parse_u32(&argc, &argv, sel, 0, 0);
9fce67dd 708 } else if (matches(*argv, "u16") == 0) {
aba5acdf
SH
709 NEXT_ARG();
710 res = parse_u16(&argc, &argv, sel, 0, 0);
9fce67dd 711 } else if (matches(*argv, "u8") == 0) {
aba5acdf
SH
712 NEXT_ARG();
713 res = parse_u8(&argc, &argv, sel, 0, 0);
9fce67dd 714 } else if (matches(*argv, "ip") == 0) {
aba5acdf
SH
715 NEXT_ARG();
716 res = parse_ip(&argc, &argv, sel);
32a121cb 717 } else if (matches(*argv, "ip6") == 0) {
aba5acdf
SH
718 NEXT_ARG();
719 res = parse_ip6(&argc, &argv, sel);
9fce67dd 720 } else if (matches(*argv, "udp") == 0) {
aba5acdf
SH
721 NEXT_ARG();
722 res = parse_udp(&argc, &argv, sel);
9fce67dd 723 } else if (matches(*argv, "tcp") == 0) {
aba5acdf
SH
724 NEXT_ARG();
725 res = parse_tcp(&argc, &argv, sel);
9fce67dd 726 } else if (matches(*argv, "icmp") == 0) {
aba5acdf
SH
727 NEXT_ARG();
728 res = parse_icmp(&argc, &argv, sel);
9fce67dd 729 } else if (matches(*argv, "mark") == 0) {
6f0ba88b 730 NEXT_ARG();
731 res = parse_mark(&argc, &argv, n);
b4d41f41
SH
732 } else if (matches(*argv, "ether") == 0) {
733 NEXT_ARG();
734 res = parse_ether(&argc, &argv, sel);
3d0b7439 735 } else
9fce67dd 736 return -1;
aba5acdf 737
aba5acdf
SH
738 *argc_p = argc;
739 *argv_p = argv;
740 return res;
741}
742
743static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
744{
745 int argc = *argc_p;
746 char **argv = *argv_p;
747
748 while (argc > 0) {
749 if (matches(*argv, "plus") == 0) {
750 int off;
32a121cb 751
aba5acdf
SH
752 NEXT_ARG();
753 if (get_integer(&off, *argv, 0))
754 return -1;
755 sel->off = off;
756 sel->flags |= TC_U32_OFFSET;
757 } else if (matches(*argv, "at") == 0) {
758 int off;
32a121cb 759
aba5acdf
SH
760 NEXT_ARG();
761 if (get_integer(&off, *argv, 0))
762 return -1;
763 sel->offoff = off;
764 if (off%2) {
765 fprintf(stderr, "offset \"at\" must be even\n");
766 return -1;
767 }
768 sel->flags |= TC_U32_VAROFFSET;
769 } else if (matches(*argv, "mask") == 0) {
aba5acdf 770 NEXT_ARG();
9f7401fa 771 if (get_be16(&sel->offmask, *argv, 16))
aba5acdf 772 return -1;
aba5acdf
SH
773 sel->flags |= TC_U32_VAROFFSET;
774 } else if (matches(*argv, "shift") == 0) {
775 int shift;
32a121cb 776
aba5acdf
SH
777 NEXT_ARG();
778 if (get_integer(&shift, *argv, 0))
779 return -1;
780 sel->offshift = shift;
781 sel->flags |= TC_U32_VAROFFSET;
782 } else if (matches(*argv, "eat") == 0) {
783 sel->flags |= TC_U32_EAT;
784 } else {
785 break;
786 }
787 argc--; argv++;
788 }
789
790 *argc_p = argc;
791 *argv_p = argv;
792 return 0;
793}
794
795static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
796{
797 int argc = *argc_p;
798 char **argv = *argv_p;
799
800 while (argc > 0) {
801 if (matches(*argv, "mask") == 0) {
aba5acdf 802 NEXT_ARG();
9f7401fa 803 if (get_be32(&sel->hmask, *argv, 16))
aba5acdf 804 return -1;
aba5acdf
SH
805 } else if (matches(*argv, "at") == 0) {
806 int num;
32a121cb 807
aba5acdf
SH
808 NEXT_ARG();
809 if (get_integer(&num, *argv, 0))
810 return -1;
811 if (num%4)
812 return -1;
813 sel->hoff = num;
814 } else {
815 break;
816 }
817 argc--; argv++;
818 }
819
820 *argc_p = argc;
821 *argv_p = argv;
822 return 0;
823}
824
1750abe2 825static void print_ipv4(FILE *f, const struct tc_u32_key *key)
6b1ac654
SH
826{
827 char abuf[256];
828
6b1ac654 829 switch (key->off) {
4c9ffc2f
SH
830 case 0:
831 switch (ntohl(key->mask)) {
832 case 0x0f000000:
82e6efe2
JHS
833 fprintf(f, "\n match IP ihl %u",
834 ntohl(key->val) >> 24);
4c9ffc2f
SH
835 return;
836 case 0x00ff0000:
82e6efe2
JHS
837 fprintf(f, "\n match IP dsfield %#x",
838 ntohl(key->val) >> 16);
4c9ffc2f
SH
839 return;
840 }
841 break;
842 case 8:
843 if (ntohl(key->mask) == 0x00ff0000) {
82e6efe2
JHS
844 fprintf(f, "\n match IP protocol %d",
845 ntohl(key->val) >> 16);
4c9ffc2f
SH
846 return;
847 }
848 break;
6b1ac654
SH
849 case 12:
850 case 16: {
851 int bits = mask2bits(key->mask);
32a121cb 852
6b1ac654 853 if (bits >= 0) {
3d0b7439 854 fprintf(f, "\n %s %s/%d",
1750abe2 855 key->off == 12 ? "match IP src" : "match IP dst",
e62077d0
SH
856 inet_ntop(AF_INET, &key->val,
857 abuf, sizeof(abuf)),
6b1ac654
SH
858 bits);
859 return;
860 }
861 }
862 break;
863
864 case 20:
4c9ffc2f
SH
865 switch (ntohl(key->mask)) {
866 case 0x0000ffff:
bcd7abdd 867 fprintf(f, "\n match dport %u",
4c9ffc2f
SH
868 ntohl(key->val) & 0xffff);
869 return;
870 case 0xffff0000:
bcd7abdd 871 fprintf(f, "\n match sport %u",
4c9ffc2f
SH
872 ntohl(key->val) >> 16);
873 return;
874 case 0xffffffff:
bcd7abdd 875 fprintf(f, "\n match dport %u, match sport %u",
4c9ffc2f
SH
876 ntohl(key->val) & 0xffff,
877 ntohl(key->val) >> 16);
878
6b1ac654
SH
879 return;
880 }
1750abe2 881 /* XXX: Default print_raw */
6b1ac654 882 }
1750abe2 883}
6b1ac654 884
d13cee6d
SH
885static void print_ipv6(FILE *f, const struct tc_u32_key *key)
886{
887 char abuf[256];
888
889 switch (key->off) {
890 case 0:
891 switch (ntohl(key->mask)) {
892 case 0x0f000000:
82e6efe2
JHS
893 fprintf(f, "\n match IP ihl %u",
894 ntohl(key->val) >> 24);
d13cee6d
SH
895 return;
896 case 0x00ff0000:
82e6efe2
JHS
897 fprintf(f, "\n match IP dsfield %#x",
898 ntohl(key->val) >> 16);
d13cee6d
SH
899 return;
900 }
901 break;
902 case 8:
903 if (ntohl(key->mask) == 0x00ff0000) {
82e6efe2
JHS
904 fprintf(f, "\n match IP protocol %d",
905 ntohl(key->val) >> 16);
d13cee6d
SH
906 return;
907 }
908 break;
909 case 12:
910 case 16: {
911 int bits = mask2bits(key->mask);
32a121cb 912
d13cee6d 913 if (bits >= 0) {
3d0b7439 914 fprintf(f, "\n %s %s/%d",
d13cee6d
SH
915 key->off == 12 ? "match IP src" : "match IP dst",
916 inet_ntop(AF_INET, &key->val,
917 abuf, sizeof(abuf)),
918 bits);
919 return;
920 }
921 }
922 break;
923
924 case 20:
925 switch (ntohl(key->mask)) {
926 case 0x0000ffff:
927 fprintf(f, "\n match sport %u",
928 ntohl(key->val) & 0xffff);
929 return;
930 case 0xffff0000:
931 fprintf(f, "\n match dport %u",
932 ntohl(key->val) >> 16);
933 return;
934 case 0xffffffff:
935 fprintf(f, "\n match sport %u, match dport %u",
936 ntohl(key->val) & 0xffff,
937 ntohl(key->val) >> 16);
938
939 return;
940 }
941 /* XXX: Default print_raw */
942 }
943}
944
1750abe2 945static void print_raw(FILE *f, const struct tc_u32_key *key)
946{
3d0b7439 947 fprintf(f, "\n match %08x/%08x at %s%d",
6b1ac654
SH
948 (unsigned int)ntohl(key->val),
949 (unsigned int)ntohl(key->mask),
950 key->offmask ? "nexthdr+" : "",
951 key->off);
952}
953
1750abe2 954static const struct {
955 __u16 proto;
956 __u16 pad;
957 void (*pprinter)(FILE *f, const struct tc_u32_key *key);
958} u32_pprinters[] = {
32a121cb 959 {0, 0, print_raw},
1750abe2 960 {ETH_P_IP, 0, print_ipv4},
d13cee6d 961 {ETH_P_IPV6, 0, print_ipv6},
1750abe2 962};
963
964static void show_keys(FILE *f, const struct tc_u32_key *key)
965{
966 int i = 0;
967
968 if (!show_pretty)
969 goto show_k;
970
32a121cb 971 for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
1750abe2 972 if (u32_pprinters[i].proto == ntohs(f_proto)) {
973show_k:
974 u32_pprinters[i].pprinter(f, key);
975 return;
976 }
977 }
978
979 i = 0;
980 goto show_k;
981}
982
983static int u32_parse_opt(struct filter_util *qu, char *handle,
6b1ac654 984 int argc, char **argv, struct nlmsghdr *n)
aba5acdf
SH
985{
986 struct {
987 struct tc_u32_sel sel;
988 struct tc_u32_key keys[128];
d17b136f 989 } sel = {};
aba5acdf
SH
990 struct tcmsg *t = NLMSG_DATA(n);
991 struct rtattr *tail;
dcf13497 992 int sel_ok = 0, terminal_ok = 0;
aba5acdf
SH
993 int sample_ok = 0;
994 __u32 htid = 0;
995 __u32 order = 0;
5e5b3008 996 __u32 flags = 0;
aba5acdf 997
aba5acdf
SH
998 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
999 fprintf(stderr, "Illegal filter ID\n");
1000 return -1;
1001 }
1002
1003 if (argc == 0)
1004 return 0;
1005
4a86fe19 1006 tail = NLMSG_TAIL(n);
2373fde9 1007 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
aba5acdf
SH
1008
1009 while (argc > 0) {
1010 if (matches(*argv, "match") == 0) {
1011 NEXT_ARG();
6f0ba88b 1012 if (parse_selector(&argc, &argv, &sel.sel, n)) {
aba5acdf
SH
1013 fprintf(stderr, "Illegal \"match\"\n");
1014 return -1;
1015 }
1016 sel_ok++;
1017 continue;
1018 } else if (matches(*argv, "offset") == 0) {
1019 NEXT_ARG();
1020 if (parse_offset(&argc, &argv, &sel.sel)) {
1021 fprintf(stderr, "Illegal \"offset\"\n");
1022 return -1;
1023 }
1024 continue;
1025 } else if (matches(*argv, "hashkey") == 0) {
1026 NEXT_ARG();
1027 if (parse_hashkey(&argc, &argv, &sel.sel)) {
1028 fprintf(stderr, "Illegal \"hashkey\"\n");
1029 return -1;
1030 }
1031 continue;
1032 } else if (matches(*argv, "classid") == 0 ||
1033 strcmp(*argv, "flowid") == 0) {
82e6efe2 1034 unsigned int flowid;
32a121cb 1035
aba5acdf 1036 NEXT_ARG();
82e6efe2 1037 if (get_tc_classid(&flowid, *argv)) {
aba5acdf
SH
1038 fprintf(stderr, "Illegal \"classid\"\n");
1039 return -1;
1040 }
82e6efe2 1041 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4);
aba5acdf
SH
1042 sel.sel.flags |= TC_U32_TERMINAL;
1043 } else if (matches(*argv, "divisor") == 0) {
32a121cb
SH
1044 unsigned int divisor;
1045
aba5acdf 1046 NEXT_ARG();
ae665a52 1047 if (get_unsigned(&divisor, *argv, 0) ||
46b67dab
SH
1048 divisor == 0 ||
1049 divisor > 0x100 || ((divisor - 1) & divisor)) {
aba5acdf
SH
1050 fprintf(stderr, "Illegal \"divisor\"\n");
1051 return -1;
1052 }
2373fde9 1053 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
aba5acdf
SH
1054 } else if (matches(*argv, "order") == 0) {
1055 NEXT_ARG();
1056 if (get_u32(&order, *argv, 0)) {
1057 fprintf(stderr, "Illegal \"order\"\n");
1058 return -1;
1059 }
1060 } else if (strcmp(*argv, "link") == 0) {
82e6efe2 1061 unsigned int linkid;
32a121cb 1062
aba5acdf 1063 NEXT_ARG();
82e6efe2 1064 if (get_u32_handle(&linkid, *argv)) {
aba5acdf
SH
1065 fprintf(stderr, "Illegal \"link\"\n");
1066 return -1;
1067 }
82e6efe2 1068 if (linkid && TC_U32_NODE(linkid)) {
aba5acdf
SH
1069 fprintf(stderr, "\"link\" must be a hash table.\n");
1070 return -1;
1071 }
58d93d00 1072 addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4);
aba5acdf 1073 } else if (strcmp(*argv, "ht") == 0) {
82e6efe2 1074 unsigned int ht;
32a121cb 1075
aba5acdf 1076 NEXT_ARG();
82e6efe2 1077 if (get_u32_handle(&ht, *argv)) {
aba5acdf
SH
1078 fprintf(stderr, "Illegal \"ht\"\n");
1079 return -1;
1080 }
82e6efe2 1081 if (handle && TC_U32_NODE(ht)) {
aba5acdf
SH
1082 fprintf(stderr, "\"ht\" must be a hash table.\n");
1083 return -1;
1084 }
1085 if (sample_ok)
82e6efe2 1086 htid = (htid & 0xFF000) | (ht & 0xFFF00000);
aba5acdf 1087 else
82e6efe2 1088 htid = (ht & 0xFFFFF000);
aba5acdf
SH
1089 } else if (strcmp(*argv, "sample") == 0) {
1090 __u32 hash;
32a121cb 1091 unsigned int divisor = 0x100;
aba5acdf
SH
1092 struct {
1093 struct tc_u32_sel sel;
1094 struct tc_u32_key keys[4];
d17b136f
PS
1095 } sel2 = {};
1096
aba5acdf 1097 NEXT_ARG();
6f0ba88b 1098 if (parse_selector(&argc, &argv, &sel2.sel, n)) {
aba5acdf
SH
1099 fprintf(stderr, "Illegal \"sample\"\n");
1100 return -1;
1101 }
1102 if (sel2.sel.nkeys != 1) {
32a121cb 1103 fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
aba5acdf
SH
1104 return -1;
1105 }
3925ad81
SH
1106 if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1107 NEXT_ARG();
82e6efe2
JHS
1108 if (get_unsigned(&divisor, *argv, 0) ||
1109 divisor == 0 || divisor > 0x100 ||
1110 ((divisor - 1) & divisor)) {
3925ad81
SH
1111 fprintf(stderr, "Illegal sample \"divisor\"\n");
1112 return -1;
1113 }
1114 NEXT_ARG();
1115 }
40eb737e
PS
1116 hash = sel2.sel.keys[0].val & sel2.sel.keys[0].mask;
1117 hash ^= hash >> 16;
1118 hash ^= hash >> 8;
1119 htid = ((hash % divisor) << 12) | (htid & 0xFFF00000);
aba5acdf
SH
1120 sample_ok = 1;
1121 continue;
2373fde9 1122 } else if (strcmp(*argv, "indev") == 0) {
d17b136f 1123 char ind[IFNAMSIZ + 1] = {};
32a121cb 1124
2373fde9
SH
1125 argc--;
1126 argv++;
1127 if (argc < 1) {
1128 fprintf(stderr, "Illegal indev\n");
1129 return -1;
1130 }
725f2a87 1131 strncpy(ind, *argv, sizeof(ind) - 1);
82e6efe2
JHS
1132 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind,
1133 strlen(ind) + 1);
d81b135b 1134
2373fde9
SH
1135 } else if (matches(*argv, "action") == 0) {
1136 NEXT_ARG();
1137 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1138 fprintf(stderr, "Illegal \"action\"\n");
1139 return -1;
1140 }
dcf13497 1141 terminal_ok++;
2373fde9 1142 continue;
d81b135b 1143
aba5acdf
SH
1144 } else if (matches(*argv, "police") == 0) {
1145 NEXT_ARG();
1146 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1147 fprintf(stderr, "Illegal \"police\"\n");
1148 return -1;
1149 }
dcf13497 1150 terminal_ok++;
aba5acdf 1151 continue;
5e5b3008
SS
1152 } else if (strcmp(*argv, "skip_hw") == 0) {
1153 NEXT_ARG();
1154 flags |= TCA_CLS_FLAGS_SKIP_HW;
1155 continue;
1156 } else if (strcmp(*argv, "skip_sw") == 0) {
1157 NEXT_ARG();
1158 flags |= TCA_CLS_FLAGS_SKIP_SW;
1159 continue;
aba5acdf
SH
1160 } else if (strcmp(*argv, "help") == 0) {
1161 explain();
1162 return -1;
1163 } else {
1164 fprintf(stderr, "What is \"%s\"?\n", *argv);
1165 explain();
1166 return -1;
1167 }
1168 argc--; argv++;
1169 }
1170
dcf13497 1171 /* We dont necessarily need class/flowids */
81c61790 1172 if (terminal_ok)
dcf13497 1173 sel.sel.flags |= TC_U32_TERMINAL;
3d0b7439 1174
aba5acdf 1175 if (order) {
82e6efe2
JHS
1176 if (TC_U32_NODE(t->tcm_handle) &&
1177 order != TC_U32_NODE(t->tcm_handle)) {
aba5acdf
SH
1178 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1179 return -1;
1180 }
1181 t->tcm_handle |= order;
1182 }
1183
1184 if (htid)
2373fde9 1185 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
aba5acdf 1186 if (sel_ok)
3d0b7439 1187 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
82e6efe2
JHS
1188 sizeof(sel.sel) +
1189 sel.sel.nkeys * sizeof(struct tc_u32_key));
5e5b3008 1190 if (flags) {
62281205
SH
1191 if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW |
1192 TCA_CLS_FLAGS_SKIP_SW))) {
1193 fprintf(stderr,
1194 "skip_hw and skip_sw are mutually exclusive\n");
5e5b3008
SS
1195 return -1;
1196 }
1197 addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
1198 }
1199
4a86fe19 1200 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
aba5acdf
SH
1201 return 0;
1202}
1203
6b1ac654
SH
1204static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1205 __u32 handle)
aba5acdf 1206{
40eb737e 1207 struct rtattr *tb[TCA_U32_MAX + 1];
aba5acdf 1208 struct tc_u32_sel *sel = NULL;
d81b135b 1209 struct tc_u32_pcnt *pf = NULL;
aba5acdf
SH
1210
1211 if (opt == NULL)
1212 return 0;
1213
ac2fc2df 1214 parse_rtattr_nested(tb, TCA_U32_MAX, opt);
aba5acdf
SH
1215
1216 if (handle) {
1217 SPRINT_BUF(b1);
1218 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1219 }
62281205
SH
1220
1221 if (TC_U32_NODE(handle))
aba5acdf 1222 fprintf(f, "order %d ", TC_U32_NODE(handle));
aba5acdf
SH
1223
1224 if (tb[TCA_U32_SEL]) {
1225 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
1226 return -1;
1227
1228 sel = RTA_DATA(tb[TCA_U32_SEL]);
1229 }
1230
1231 if (tb[TCA_U32_DIVISOR]) {
82e6efe2
JHS
1232 fprintf(f, "ht divisor %d ",
1233 rta_getattr_u32(tb[TCA_U32_DIVISOR]));
aba5acdf 1234 } else if (tb[TCA_U32_HASH]) {
ff24746c 1235 __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]);
32a121cb 1236
e62077d0
SH
1237 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1238 TC_U32_HASH(htid));
aba5acdf
SH
1239 } else {
1240 fprintf(f, "??? ");
1241 }
1242 if (tb[TCA_U32_CLASSID]) {
1243 SPRINT_BUF(b1);
1244 fprintf(f, "%sflowid %s ",
40eb737e 1245 !sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "",
82e6efe2
JHS
1246 sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]),
1247 b1));
40eb737e 1248 } else if (sel && sel->flags & TC_U32_TERMINAL) {
aba5acdf
SH
1249 fprintf(f, "terminal flowid ??? ");
1250 }
1251 if (tb[TCA_U32_LINK]) {
1252 SPRINT_BUF(b1);
e62077d0 1253 fprintf(f, "link %s ",
82e6efe2
JHS
1254 sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]),
1255 b1));
aba5acdf 1256 }
2373fde9 1257
5e5b3008
SS
1258 if (tb[TCA_U32_FLAGS]) {
1259 __u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]);
1260
1261 if (flags & TCA_CLS_FLAGS_SKIP_HW)
1262 fprintf(f, "skip_hw ");
1263 if (flags & TCA_CLS_FLAGS_SKIP_SW)
1264 fprintf(f, "skip_sw ");
e57285b8
OG
1265
1266 if (flags & TCA_CLS_FLAGS_IN_HW)
1267 fprintf(f, "in_hw ");
1268 else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
1269 fprintf(f, "not_in_hw ");
5e5b3008
SS
1270 }
1271
d81b135b 1272 if (tb[TCA_U32_PCNT]) {
1273 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) {
32a121cb 1274 fprintf(f, "Broken perf counters\n");
d81b135b 1275 return -1;
1276 }
1277 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1278 }
aba5acdf 1279
6f0ba88b 1280 if (sel && show_stats && NULL != pf)
b906243b 1281 fprintf(f, " (rule hit %llu success %llu)",
1282 (unsigned long long) pf->rcnt,
1283 (unsigned long long) pf->rhit);
6f0ba88b 1284
1285 if (tb[TCA_U32_MARK]) {
1286 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
32a121cb 1287
6f0ba88b 1288 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1289 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1290 } else {
1291 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)",
1292 mark->val, mark->mask, mark->success);
1293 }
1294 }
1295
aba5acdf 1296 if (sel) {
aba5acdf 1297 if (sel->nkeys) {
6b1ac654 1298 int i;
32a121cb 1299
dd0c8d19 1300 for (i = 0; i < sel->nkeys; i++) {
1750abe2 1301 show_keys(f, sel->keys + i);
d81b135b 1302 if (show_stats && NULL != pf)
6b1ac654 1303 fprintf(f, " (success %llu ) ",
b906243b 1304 (unsigned long long) pf->kcnts[i]);
2373fde9 1305 }
aba5acdf
SH
1306 }
1307
40eb737e 1308 if (sel->flags & (TC_U32_VAROFFSET | TC_U32_OFFSET)) {
aba5acdf 1309 fprintf(f, "\n offset ");
40eb737e 1310 if (sel->flags & TC_U32_VAROFFSET)
e62077d0
SH
1311 fprintf(f, "%04x>>%d at %d ",
1312 ntohs(sel->offmask),
1313 sel->offshift, sel->offoff);
aba5acdf
SH
1314 if (sel->off)
1315 fprintf(f, "plus %d ", sel->off);
1316 }
40eb737e 1317 if (sel->flags & TC_U32_EAT)
aba5acdf
SH
1318 fprintf(f, " eat ");
1319
1320 if (sel->hmask) {
1321 fprintf(f, "\n hash mask %08x at %d ",
1322 (unsigned int)htonl(sel->hmask), sel->hoff);
1323 }
1324 }
1325
2373fde9
SH
1326 if (tb[TCA_U32_POLICE]) {
1327 fprintf(f, "\n");
1328 tc_print_police(f, tb[TCA_U32_POLICE]);
1329 }
62281205 1330
2373fde9
SH
1331 if (tb[TCA_U32_INDEV]) {
1332 struct rtattr *idev = tb[TCA_U32_INDEV];
32a121cb 1333
ff24746c 1334 fprintf(f, "\n input dev %s\n", rta_getattr_str(idev));
2373fde9 1335 }
62281205
SH
1336
1337 if (tb[TCA_U32_ACT])
9e713525 1338 tc_print_action(f, tb[TCA_U32_ACT], 0);
2373fde9 1339
aba5acdf
SH
1340 return 0;
1341}
1342
6b7dff17
SH
1343struct filter_util u32_filter_util = {
1344 .id = "u32",
1345 .parse_fopt = u32_parse_opt,
1346 .print_fopt = u32_print_opt,
aba5acdf 1347};