]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/f_u32.c
Fixes for tc hash sample.
[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>
17#include <syslog.h>
18#include <fcntl.h>
19#include <sys/socket.h>
3925ad81 20#include <sys/utsname.h>
aba5acdf
SH
21#include <netinet/in.h>
22#include <arpa/inet.h>
23#include <string.h>
2373fde9 24#include <linux/if.h>
aba5acdf
SH
25
26#include "utils.h"
27#include "tc_util.h"
28
29static void explain(void)
30{
31 fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n");
32 fprintf(stderr, " [ police POLICE_SPEC ] [ offset OFFSET_SPEC ]\n");
33 fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
34 fprintf(stderr, " [ sample SAMPLE ]\n");
35 fprintf(stderr, "or u32 divisor DIVISOR\n");
36 fprintf(stderr, "\n");
37 fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
3925ad81 38 fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
aba5acdf
SH
39 fprintf(stderr, " FILTERID := X:Y:Z\n");
40}
41
42#define usage() return(-1)
43
44int get_u32_handle(__u32 *handle, char *str)
45{
46 __u32 htid=0, hash=0, nodeid=0;
47 char *tmp = strchr(str, ':');
48
49 if (tmp == NULL) {
50 if (memcmp("0x", str, 2) == 0)
51 return get_u32(handle, str, 16);
52 return -1;
53 }
54 htid = strtoul(str, &tmp, 16);
55 if (tmp == str && *str != ':' && *str != 0)
56 return -1;
57 if (htid>=0x1000)
58 return -1;
59 if (*tmp) {
60 str = tmp+1;
61 hash = strtoul(str, &tmp, 16);
62 if (tmp == str && *str != ':' && *str != 0)
63 return -1;
64 if (hash>=0x100)
65 return -1;
66 if (*tmp) {
67 str = tmp+1;
68 nodeid = strtoul(str, &tmp, 16);
69 if (tmp == str && *str != 0)
70 return -1;
71 if (nodeid>=0x1000)
72 return -1;
73 }
74 }
75 *handle = (htid<<20)|(hash<<12)|nodeid;
76 return 0;
77}
78
79char * sprint_u32_handle(__u32 handle, char *buf)
80{
81 int bsize = SPRINT_BSIZE-1;
82 __u32 htid = TC_U32_HTID(handle);
83 __u32 hash = TC_U32_HASH(handle);
84 __u32 nodeid = TC_U32_NODE(handle);
85 char *b = buf;
86
87 if (handle == 0) {
88 snprintf(b, bsize, "none");
89 return b;
90 }
91 if (htid) {
92 int l = snprintf(b, bsize, "%x:", htid>>20);
93 bsize -= l;
94 b += l;
95 }
96 if (nodeid|hash) {
97 if (hash) {
98 int l = snprintf(b, bsize, "%x", hash);
99 bsize -= l;
100 b += l;
101 }
102 if (nodeid) {
103 int l = snprintf(b, bsize, ":%x", nodeid);
104 bsize -= l;
105 b += l;
106 }
107 }
108 if (show_raw)
109 snprintf(b, bsize, "[%08x] ", handle);
110 return buf;
111}
112
113static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
114{
115 int i;
116 int hwm = sel->nkeys;
117
118 key &= mask;
119
120 for (i=0; i<hwm; i++) {
121 if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
122 __u32 intersect = mask&sel->keys[i].mask;
123
124 if ((key^sel->keys[i].val) & intersect)
125 return -1;
126 sel->keys[i].val |= key;
127 sel->keys[i].mask |= mask;
128 return 0;
129 }
130 }
131
132 if (hwm >= 128)
133 return -1;
134 if (off % 4)
135 return -1;
136 sel->keys[hwm].val = key;
137 sel->keys[hwm].mask = mask;
138 sel->keys[hwm].off = off;
139 sel->keys[hwm].offmask = offmask;
140 sel->nkeys++;
141 return 0;
142}
143
144static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
145{
146 key = htonl(key);
147 mask = htonl(mask);
148 return pack_key(sel, key, mask, off, offmask);
149}
150
151static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
152{
153 if (key > 0xFFFF || mask > 0xFFFF)
154 return -1;
155
156 if ((off & 3) == 0) {
157 key <<= 16;
158 mask <<= 16;
159 }
160 off &= ~3;
161 key = htonl(key);
162 mask = htonl(mask);
163
164 return pack_key(sel, key, mask, off, offmask);
165}
166
167static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
168{
169 if (key > 0xFF || mask > 0xFF)
170 return -1;
171
172 if ((off & 3) == 0) {
173 key <<= 24;
174 mask <<= 24;
175 } else if ((off & 3) == 1) {
176 key <<= 16;
177 mask <<= 16;
178 } else if ((off & 3) == 2) {
179 key <<= 8;
180 mask <<= 8;
181 }
182 off &= ~3;
183 key = htonl(key);
184 mask = htonl(mask);
185
186 return pack_key(sel, key, mask, off, offmask);
187}
188
189
190int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
191{
192 int argc = *argc_p;
193 char **argv = *argv_p;
194 char *p = *argv;
195
196 if (argc <= 0)
197 return -1;
198
199 if (strlen(p) > strlen("nexthdr+") &&
200 memcmp(p, "nexthdr+", strlen("nexthdr+")) == 0) {
201 *offmask = -1;
202 p += strlen("nexthdr+");
203 } else if (matches(*argv, "nexthdr+") == 0) {
204 NEXT_ARG();
205 *offmask = -1;
206 p = *argv;
207 }
208
209 if (get_integer(off, p, 0))
210 return -1;
211 argc--; argv++;
212
213 *argc_p = argc;
214 *argv_p = argv;
215 return 0;
216}
217
218
219static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
220{
221 int res = -1;
222 int argc = *argc_p;
223 char **argv = *argv_p;
224 __u32 key;
225 __u32 mask;
226
227 if (argc < 2)
228 return -1;
229
230 if (get_u32(&key, *argv, 0))
231 return -1;
232 argc--; argv++;
233
234 if (get_u32(&mask, *argv, 16))
235 return -1;
236 argc--; argv++;
237
238 if (argc > 0 && strcmp(argv[0], "at") == 0) {
239 NEXT_ARG();
240 if (parse_at(&argc, &argv, &off, &offmask))
241 return -1;
242 }
243
244 res = pack_key32(sel, key, mask, off, offmask);
245 *argc_p = argc;
246 *argv_p = argv;
247 return res;
248}
249
250static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
251{
252 int res = -1;
253 int argc = *argc_p;
254 char **argv = *argv_p;
255 __u32 key;
256 __u32 mask;
257
258 if (argc < 2)
259 return -1;
260
261 if (get_u32(&key, *argv, 0))
262 return -1;
263 argc--; argv++;
264
265 if (get_u32(&mask, *argv, 16))
266 return -1;
267 argc--; argv++;
268
269 if (argc > 0 && strcmp(argv[0], "at") == 0) {
270 NEXT_ARG();
271 if (parse_at(&argc, &argv, &off, &offmask))
272 return -1;
273 }
274 res = pack_key16(sel, key, mask, off, offmask);
275 *argc_p = argc;
276 *argv_p = argv;
277 return res;
278}
279
280static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
281{
282 int res = -1;
283 int argc = *argc_p;
284 char **argv = *argv_p;
285 __u32 key;
286 __u32 mask;
287
288 if (argc < 2)
289 return -1;
290
291 if (get_u32(&key, *argv, 0))
292 return -1;
293 argc--; argv++;
294
295 if (get_u32(&mask, *argv, 16))
296 return -1;
297 argc--; argv++;
298
299 if (key > 0xFF || mask > 0xFF)
300 return -1;
301
302 if (argc > 0 && strcmp(argv[0], "at") == 0) {
303 NEXT_ARG();
304 if (parse_at(&argc, &argv, &off, &offmask))
305 return -1;
306 }
307
308 res = pack_key8(sel, key, mask, off, offmask);
309 *argc_p = argc;
310 *argv_p = argv;
311 return res;
312}
313
314static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off)
315{
316 int res = -1;
317 int argc = *argc_p;
318 char **argv = *argv_p;
319 inet_prefix addr;
320 __u32 mask;
321 int offmask = 0;
322
323 if (argc < 1)
324 return -1;
325
326 if (get_prefix_1(&addr, *argv, AF_INET))
327 return -1;
328 argc--; argv++;
329
330 if (argc > 0 && strcmp(argv[0], "at") == 0) {
331 NEXT_ARG();
332 if (parse_at(&argc, &argv, &off, &offmask))
333 return -1;
334 }
335
336 mask = 0;
337 if (addr.bitlen)
338 mask = htonl(0xFFFFFFFF<<(32-addr.bitlen));
339 if (pack_key(sel, addr.data[0], mask, off, offmask) < 0)
340 return -1;
341 res = 0;
342
343 *argc_p = argc;
344 *argv_p = argv;
345 return res;
346}
347
348static int parse_ip6_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off)
349{
350 int res = -1;
351 int argc = *argc_p;
352 char **argv = *argv_p;
353 int plen = 128;
354 int i;
355 inet_prefix addr;
356 int offmask = 0;
357
358 if (argc < 1)
359 return -1;
360
361 if (get_prefix_1(&addr, *argv, AF_INET6))
362 return -1;
363 argc--; argv++;
364
365 if (argc > 0 && strcmp(argv[0], "at") == 0) {
366 NEXT_ARG();
367 if (parse_at(&argc, &argv, &off, &offmask))
368 return -1;
369 }
370
371 plen = addr.bitlen;
372 for (i=0; i<plen; i+=32) {
2373fde9
SH
373// if (((i+31)&~0x1F)<=plen) {
374 if (((i+31))<=plen) {
aba5acdf
SH
375 if ((res = pack_key(sel, addr.data[i/32], 0xFFFFFFFF, off+4*(i/32), offmask)) < 0)
376 return -1;
377 } else if (i<plen) {
378 __u32 mask = htonl(0xFFFFFFFF<<(32-(plen-i)));
379 if ((res = pack_key(sel, addr.data[i/32], mask, off+4*(i/32), offmask)) < 0)
380 return -1;
381 }
382 }
383 res = 0;
384
385 *argc_p = argc;
386 *argv_p = argv;
387 return res;
388}
389
390static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
391{
392 int res = -1;
393 int argc = *argc_p;
394 char **argv = *argv_p;
395
396 if (argc < 2)
397 return -1;
398
399 if (strcmp(*argv, "src") == 0) {
400 NEXT_ARG();
401 res = parse_ip_addr(&argc, &argv, sel, 12);
402 goto done;
403 }
404 if (strcmp(*argv, "dst") == 0) {
405 NEXT_ARG();
406 res = parse_ip_addr(&argc, &argv, sel, 16);
407 goto done;
408 }
409 if (strcmp(*argv, "tos") == 0 ||
410 matches(*argv, "dsfield") == 0) {
411 NEXT_ARG();
412 res = parse_u8(&argc, &argv, sel, 1, 0);
413 goto done;
414 }
415 if (strcmp(*argv, "ihl") == 0) {
416 NEXT_ARG();
417 res = parse_u8(&argc, &argv, sel, 0, 0);
418 goto done;
419 }
420 if (strcmp(*argv, "protocol") == 0) {
421 NEXT_ARG();
422 res = parse_u8(&argc, &argv, sel, 9, 0);
423 goto done;
424 }
425 if (matches(*argv, "precedence") == 0) {
426 NEXT_ARG();
427 res = parse_u8(&argc, &argv, sel, 1, 0);
428 goto done;
429 }
430 if (strcmp(*argv, "nofrag") == 0) {
431 argc--; argv++;
432 res = pack_key16(sel, 0, 0x3FFF, 6, 0);
433 goto done;
434 }
435 if (strcmp(*argv, "firstfrag") == 0) {
436 argc--; argv++;
437 res = pack_key16(sel, 0, 0x1FFF, 6, 0);
438 goto done;
439 }
440 if (strcmp(*argv, "df") == 0) {
441 argc--; argv++;
442 res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
443 goto done;
444 }
445 if (strcmp(*argv, "mf") == 0) {
446 argc--; argv++;
447 res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
448 goto done;
449 }
450 if (strcmp(*argv, "dport") == 0) {
451 NEXT_ARG();
452 res = parse_u16(&argc, &argv, sel, 22, 0);
453 goto done;
454 }
455 if (strcmp(*argv, "sport") == 0) {
456 NEXT_ARG();
457 res = parse_u16(&argc, &argv, sel, 20, 0);
458 goto done;
459 }
460 if (strcmp(*argv, "icmp_type") == 0) {
461 NEXT_ARG();
462 res = parse_u8(&argc, &argv, sel, 20, 0);
463 goto done;
464 }
465 if (strcmp(*argv, "icmp_code") == 0) {
466 NEXT_ARG();
467 res = parse_u8(&argc, &argv, sel, 20, 1);
468 goto done;
469 }
470 return -1;
471
472done:
473 *argc_p = argc;
474 *argv_p = argv;
475 return res;
476}
477
478static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
479{
480 int res = -1;
481 int argc = *argc_p;
482 char **argv = *argv_p;
483
484 if (argc < 2)
485 return -1;
486
487 if (strcmp(*argv, "src") == 0) {
488 NEXT_ARG();
489 res = parse_ip6_addr(&argc, &argv, sel, 8);
490 goto done;
491 }
492 if (strcmp(*argv, "dst") == 0) {
493 NEXT_ARG();
494 res = parse_ip6_addr(&argc, &argv, sel, 24);
495 goto done;
496 }
497 if (strcmp(*argv, "priority") == 0) {
498 NEXT_ARG();
d8a45819 499 res = parse_u8(&argc, &argv, sel, 4, 0);
aba5acdf
SH
500 goto done;
501 }
502 if (strcmp(*argv, "protocol") == 0) {
503 NEXT_ARG();
504 res = parse_u8(&argc, &argv, sel, 6, 0);
505 goto done;
506 }
507 if (strcmp(*argv, "flowlabel") == 0) {
508 NEXT_ARG();
509 res = parse_u32(&argc, &argv, sel, 0, 0);
510 goto done;
511 }
512 if (strcmp(*argv, "dport") == 0) {
513 NEXT_ARG();
514 res = parse_u16(&argc, &argv, sel, 42, 0);
515 goto done;
516 }
517 if (strcmp(*argv, "sport") == 0) {
518 NEXT_ARG();
519 res = parse_u16(&argc, &argv, sel, 40, 0);
520 goto done;
521 }
522 if (strcmp(*argv, "icmp_type") == 0) {
523 NEXT_ARG();
524 res = parse_u8(&argc, &argv, sel, 40, 0);
525 goto done;
526 }
527 if (strcmp(*argv, "icmp_code") == 0) {
528 NEXT_ARG();
529 res = parse_u8(&argc, &argv, sel, 41, 1);
530 goto done;
531 }
532 return -1;
533
534done:
535 *argc_p = argc;
536 *argv_p = argv;
537 return res;
538}
539
540#define parse_tcp parse_udp
541static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
542{
543 int res = -1;
544 int argc = *argc_p;
545 char **argv = *argv_p;
546
547 if (argc < 2)
548 return -1;
549
550 if (strcmp(*argv, "src") == 0) {
551 NEXT_ARG();
552 res = parse_u16(&argc, &argv, sel, 0, -1);
553 goto done;
554 }
555 if (strcmp(*argv, "dst") == 0) {
556 NEXT_ARG();
557 res = parse_u16(&argc, &argv, sel, 2, -1);
558 goto done;
559 }
560 return -1;
561
562done:
563 *argc_p = argc;
564 *argv_p = argv;
565 return res;
566}
567
568static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
569{
570 int res = -1;
571 int argc = *argc_p;
572 char **argv = *argv_p;
573
574 if (argc < 2)
575 return -1;
576
577 if (strcmp(*argv, "type") == 0) {
578 NEXT_ARG();
579 res = parse_u8(&argc, &argv, sel, 0, -1);
580 goto done;
581 }
582 if (strcmp(*argv, "code") == 0) {
583 NEXT_ARG();
584 res = parse_u8(&argc, &argv, sel, 1, -1);
585 goto done;
586 }
587 return -1;
588
589done:
590 *argc_p = argc;
591 *argv_p = argv;
592 return res;
593}
594
6f0ba88b 595static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
596{
597 int res = -1;
598 int argc = *argc_p;
599 char **argv = *argv_p;
600 struct tc_u32_mark mark;
601
602 if (argc <= 1)
603 return -1;
604
605 if (get_u32(&mark.val, *argv, 0)) {
606 fprintf(stderr, "Illegal \"mark\" value\n");
607 return -1;
608 }
609 NEXT_ARG();
610
611 if (get_u32(&mark.mask, *argv, 0)) {
612 fprintf(stderr, "Illegal \"mark\" mask\n");
613 return -1;
614 }
615 NEXT_ARG();
616
617 if ((mark.val & mark.mask) != mark.val) {
618 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
619 return -1;
620 }
aba5acdf 621
6f0ba88b 622 addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
623 res = 0;
624
625 *argc_p = argc;
626 *argv_p = argv;
627 return res;
628}
aba5acdf 629
6f0ba88b 630static int parse_selector(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, struct nlmsghdr *n)
aba5acdf
SH
631{
632 int argc = *argc_p;
633 char **argv = *argv_p;
634 int res = -1;
635
636 if (argc <= 0)
637 return -1;
638
639 if (matches(*argv, "u32") == 0) {
640 NEXT_ARG();
641 res = parse_u32(&argc, &argv, sel, 0, 0);
642 goto done;
643 }
644 if (matches(*argv, "u16") == 0) {
645 NEXT_ARG();
646 res = parse_u16(&argc, &argv, sel, 0, 0);
647 goto done;
648 }
649 if (matches(*argv, "u8") == 0) {
650 NEXT_ARG();
651 res = parse_u8(&argc, &argv, sel, 0, 0);
652 goto done;
653 }
654 if (matches(*argv, "ip") == 0) {
655 NEXT_ARG();
656 res = parse_ip(&argc, &argv, sel);
657 goto done;
658 }
659 if (matches(*argv, "ip6") == 0) {
660 NEXT_ARG();
661 res = parse_ip6(&argc, &argv, sel);
662 goto done;
663 }
664 if (matches(*argv, "udp") == 0) {
665 NEXT_ARG();
666 res = parse_udp(&argc, &argv, sel);
667 goto done;
668 }
669 if (matches(*argv, "tcp") == 0) {
670 NEXT_ARG();
671 res = parse_tcp(&argc, &argv, sel);
672 goto done;
673 }
674 if (matches(*argv, "icmp") == 0) {
675 NEXT_ARG();
676 res = parse_icmp(&argc, &argv, sel);
677 goto done;
678 }
6f0ba88b 679 if (matches(*argv, "mark") == 0) {
680 NEXT_ARG();
681 res = parse_mark(&argc, &argv, n);
682 goto done;
683 }
684
aba5acdf
SH
685 return -1;
686
687done:
688 *argc_p = argc;
689 *argv_p = argv;
690 return res;
691}
692
693static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
694{
695 int argc = *argc_p;
696 char **argv = *argv_p;
697
698 while (argc > 0) {
699 if (matches(*argv, "plus") == 0) {
700 int off;
701 NEXT_ARG();
702 if (get_integer(&off, *argv, 0))
703 return -1;
704 sel->off = off;
705 sel->flags |= TC_U32_OFFSET;
706 } else if (matches(*argv, "at") == 0) {
707 int off;
708 NEXT_ARG();
709 if (get_integer(&off, *argv, 0))
710 return -1;
711 sel->offoff = off;
712 if (off%2) {
713 fprintf(stderr, "offset \"at\" must be even\n");
714 return -1;
715 }
716 sel->flags |= TC_U32_VAROFFSET;
717 } else if (matches(*argv, "mask") == 0) {
718 __u16 mask;
719 NEXT_ARG();
720 if (get_u16(&mask, *argv, 16))
721 return -1;
722 sel->offmask = htons(mask);
723 sel->flags |= TC_U32_VAROFFSET;
724 } else if (matches(*argv, "shift") == 0) {
725 int shift;
726 NEXT_ARG();
727 if (get_integer(&shift, *argv, 0))
728 return -1;
729 sel->offshift = shift;
730 sel->flags |= TC_U32_VAROFFSET;
731 } else if (matches(*argv, "eat") == 0) {
732 sel->flags |= TC_U32_EAT;
733 } else {
734 break;
735 }
736 argc--; argv++;
737 }
738
739 *argc_p = argc;
740 *argv_p = argv;
741 return 0;
742}
743
744static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
745{
746 int argc = *argc_p;
747 char **argv = *argv_p;
748
749 while (argc > 0) {
750 if (matches(*argv, "mask") == 0) {
751 __u32 mask;
752 NEXT_ARG();
753 if (get_u32(&mask, *argv, 16))
754 return -1;
755 sel->hmask = htonl(mask);
756 } else if (matches(*argv, "at") == 0) {
757 int num;
758 NEXT_ARG();
759 if (get_integer(&num, *argv, 0))
760 return -1;
761 if (num%4)
762 return -1;
763 sel->hoff = num;
764 } else {
765 break;
766 }
767 argc--; argv++;
768 }
769
770 *argc_p = argc;
771 *argv_p = argv;
772 return 0;
773}
774
775static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)
776{
777 struct {
778 struct tc_u32_sel sel;
779 struct tc_u32_key keys[128];
780 } sel;
781 struct tcmsg *t = NLMSG_DATA(n);
782 struct rtattr *tail;
783 int sel_ok = 0;
784 int sample_ok = 0;
785 __u32 htid = 0;
786 __u32 order = 0;
787
788 memset(&sel, 0, sizeof(sel));
789
790 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
791 fprintf(stderr, "Illegal filter ID\n");
792 return -1;
793 }
794
795 if (argc == 0)
796 return 0;
797
4a86fe19 798 tail = NLMSG_TAIL(n);
2373fde9 799 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
aba5acdf
SH
800
801 while (argc > 0) {
802 if (matches(*argv, "match") == 0) {
803 NEXT_ARG();
6f0ba88b 804 if (parse_selector(&argc, &argv, &sel.sel, n)) {
aba5acdf
SH
805 fprintf(stderr, "Illegal \"match\"\n");
806 return -1;
807 }
808 sel_ok++;
809 continue;
810 } else if (matches(*argv, "offset") == 0) {
811 NEXT_ARG();
812 if (parse_offset(&argc, &argv, &sel.sel)) {
813 fprintf(stderr, "Illegal \"offset\"\n");
814 return -1;
815 }
816 continue;
817 } else if (matches(*argv, "hashkey") == 0) {
818 NEXT_ARG();
819 if (parse_hashkey(&argc, &argv, &sel.sel)) {
820 fprintf(stderr, "Illegal \"hashkey\"\n");
821 return -1;
822 }
823 continue;
824 } else if (matches(*argv, "classid") == 0 ||
825 strcmp(*argv, "flowid") == 0) {
826 unsigned handle;
827 NEXT_ARG();
828 if (get_tc_classid(&handle, *argv)) {
829 fprintf(stderr, "Illegal \"classid\"\n");
830 return -1;
831 }
2373fde9 832 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4);
aba5acdf
SH
833 sel.sel.flags |= TC_U32_TERMINAL;
834 } else if (matches(*argv, "divisor") == 0) {
835 unsigned divisor;
836 NEXT_ARG();
837 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
3925ad81 838 divisor > 0x100 || (divisor - 1 & divisor)) {
aba5acdf
SH
839 fprintf(stderr, "Illegal \"divisor\"\n");
840 return -1;
841 }
2373fde9 842 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
aba5acdf
SH
843 } else if (matches(*argv, "order") == 0) {
844 NEXT_ARG();
845 if (get_u32(&order, *argv, 0)) {
846 fprintf(stderr, "Illegal \"order\"\n");
847 return -1;
848 }
849 } else if (strcmp(*argv, "link") == 0) {
850 unsigned handle;
851 NEXT_ARG();
852 if (get_u32_handle(&handle, *argv)) {
853 fprintf(stderr, "Illegal \"link\"\n");
854 return -1;
855 }
856 if (handle && TC_U32_NODE(handle)) {
857 fprintf(stderr, "\"link\" must be a hash table.\n");
858 return -1;
859 }
2373fde9 860 addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4);
aba5acdf
SH
861 } else if (strcmp(*argv, "ht") == 0) {
862 unsigned handle;
863 NEXT_ARG();
864 if (get_u32_handle(&handle, *argv)) {
865 fprintf(stderr, "Illegal \"ht\"\n");
866 return -1;
867 }
868 if (handle && TC_U32_NODE(handle)) {
869 fprintf(stderr, "\"ht\" must be a hash table.\n");
870 return -1;
871 }
872 if (sample_ok)
873 htid = (htid&0xFF000)|(handle&0xFFF00000);
874 else
875 htid = (handle&0xFFFFF000);
876 } else if (strcmp(*argv, "sample") == 0) {
877 __u32 hash;
3925ad81
SH
878 unsigned divisor = 0x100;
879 struct utsname utsname;
aba5acdf
SH
880 struct {
881 struct tc_u32_sel sel;
882 struct tc_u32_key keys[4];
883 } sel2;
f3b1006c 884 memset(sel2, 0, sizeof(sel32));
aba5acdf 885 NEXT_ARG();
6f0ba88b 886 if (parse_selector(&argc, &argv, &sel2.sel, n)) {
aba5acdf
SH
887 fprintf(stderr, "Illegal \"sample\"\n");
888 return -1;
889 }
890 if (sel2.sel.nkeys != 1) {
891 fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
892 return -1;
893 }
3925ad81
SH
894 if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
895 NEXT_ARG();
896 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
897 divisor > 0x100 || (divisor - 1 & divisor)) {
898 fprintf(stderr, "Illegal sample \"divisor\"\n");
899 return -1;
900 }
901 NEXT_ARG();
902 }
aba5acdf 903 hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask;
3925ad81
SH
904 uname(&utsname);
905 if (strncmp(utsname.release, "2.4.", 4) == 0) {
906 hash ^= hash>>16;
907 hash ^= hash>>8;
908 }
909 else {
910 __u32 mask = sel2.sel.keys[0].mask;
911 while (mask && !(mask & 1)) {
912 mask >>= 1;
913 hash >>= 1;
914 }
915 hash &= 0xFF;
916 }
917 htid = ((hash%divisor)<<12)|(htid&0xFFF00000);
aba5acdf
SH
918 sample_ok = 1;
919 continue;
2373fde9
SH
920 } else if (strcmp(*argv, "indev") == 0) {
921 char ind[IFNAMSIZ + 1];
922 memset(ind, 0, sizeof (ind));
923 argc--;
924 argv++;
925 if (argc < 1) {
926 fprintf(stderr, "Illegal indev\n");
927 return -1;
928 }
929 strncpy(ind, *argv, sizeof (ind) - 1);
930 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1);
d81b135b 931
2373fde9
SH
932 } else if (matches(*argv, "action") == 0) {
933 NEXT_ARG();
934 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
935 fprintf(stderr, "Illegal \"action\"\n");
936 return -1;
937 }
938 continue;
d81b135b 939
aba5acdf
SH
940 } else if (matches(*argv, "police") == 0) {
941 NEXT_ARG();
942 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
943 fprintf(stderr, "Illegal \"police\"\n");
944 return -1;
945 }
946 continue;
947 } else if (strcmp(*argv, "help") == 0) {
948 explain();
949 return -1;
950 } else {
951 fprintf(stderr, "What is \"%s\"?\n", *argv);
952 explain();
953 return -1;
954 }
955 argc--; argv++;
956 }
957
958 if (order) {
959 if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
960 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
961 return -1;
962 }
963 t->tcm_handle |= order;
964 }
965
966 if (htid)
2373fde9 967 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
aba5acdf 968 if (sel_ok)
2373fde9 969 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
4a86fe19 970 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
aba5acdf
SH
971 return 0;
972}
973
974static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle)
975{
976 struct rtattr *tb[TCA_U32_MAX+1];
977 struct tc_u32_sel *sel = NULL;
d81b135b 978 struct tc_u32_pcnt *pf = NULL;
aba5acdf
SH
979
980 if (opt == NULL)
981 return 0;
982
ac2fc2df 983 parse_rtattr_nested(tb, TCA_U32_MAX, opt);
aba5acdf
SH
984
985 if (handle) {
986 SPRINT_BUF(b1);
987 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
988 }
989 if (TC_U32_NODE(handle)) {
990 fprintf(f, "order %d ", TC_U32_NODE(handle));
991 }
992
993 if (tb[TCA_U32_SEL]) {
994 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
995 return -1;
996
997 sel = RTA_DATA(tb[TCA_U32_SEL]);
998 }
999
1000 if (tb[TCA_U32_DIVISOR]) {
1001 fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR]));
1002 } else if (tb[TCA_U32_HASH]) {
1003 __u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]);
1004 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid), TC_U32_HASH(htid));
1005 } else {
1006 fprintf(f, "??? ");
1007 }
1008 if (tb[TCA_U32_CLASSID]) {
1009 SPRINT_BUF(b1);
1010 fprintf(f, "%sflowid %s ",
1011 !sel || !(sel->flags&TC_U32_TERMINAL) ? "*" : "",
1012 sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_U32_CLASSID]), b1));
1013 } else if (sel && sel->flags&TC_U32_TERMINAL) {
1014 fprintf(f, "terminal flowid ??? ");
1015 }
1016 if (tb[TCA_U32_LINK]) {
1017 SPRINT_BUF(b1);
1018 fprintf(f, "link %s ", sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
1019 }
2373fde9 1020
d81b135b 1021 if (tb[TCA_U32_PCNT]) {
1022 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) {
1023 fprintf(f, "Broken perf counters \n");
1024 return -1;
1025 }
1026 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1027 }
aba5acdf 1028
6f0ba88b 1029 if (sel && show_stats && NULL != pf)
b906243b 1030 fprintf(f, " (rule hit %llu success %llu)",
1031 (unsigned long long) pf->rcnt,
1032 (unsigned long long) pf->rhit);
6f0ba88b 1033
1034 if (tb[TCA_U32_MARK]) {
1035 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1036 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1037 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1038 } else {
1039 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)",
1040 mark->val, mark->mask, mark->success);
1041 }
1042 }
1043
aba5acdf
SH
1044 if (sel) {
1045 int i;
1046 struct tc_u32_key *key = sel->keys;
aba5acdf 1047 if (sel->nkeys) {
2373fde9 1048 for (i=0; i<sel->nkeys; i++, key++) {
aba5acdf
SH
1049 fprintf(f, "\n match %08x/%08x at %s%d",
1050 (unsigned int)ntohl(key->val),
1051 (unsigned int)ntohl(key->mask),
1052 key->offmask ? "nexthdr+" : "",
1053 key->off);
d81b135b 1054 if (show_stats && NULL != pf)
b906243b 1055 fprintf(f, " (success %lld ) ",
1056 (unsigned long long) pf->kcnts[i]);
2373fde9 1057 }
aba5acdf
SH
1058 }
1059
1060 if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) {
1061 fprintf(f, "\n offset ");
1062 if (sel->flags&TC_U32_VAROFFSET)
1063 fprintf(f, "%04x>>%d at %d ", ntohs(sel->offmask), sel->offshift, sel->offoff);
1064 if (sel->off)
1065 fprintf(f, "plus %d ", sel->off);
1066 }
1067 if (sel->flags&TC_U32_EAT)
1068 fprintf(f, " eat ");
1069
1070 if (sel->hmask) {
1071 fprintf(f, "\n hash mask %08x at %d ",
1072 (unsigned int)htonl(sel->hmask), sel->hoff);
1073 }
1074 }
1075
2373fde9
SH
1076 if (tb[TCA_U32_POLICE]) {
1077 fprintf(f, "\n");
1078 tc_print_police(f, tb[TCA_U32_POLICE]);
1079 }
1080 if (tb[TCA_U32_INDEV]) {
1081 struct rtattr *idev = tb[TCA_U32_INDEV];
1082 fprintf(f, "\n input dev %s\n", (char *) RTA_DATA(idev));
1083 }
1084 if (tb[TCA_U32_ACT]) {
1085 tc_print_action(f, tb[TCA_U32_ACT]);
1086 }
1087
aba5acdf
SH
1088 return 0;
1089}
1090
6b7dff17
SH
1091struct filter_util u32_filter_util = {
1092 .id = "u32",
1093 .parse_fopt = u32_parse_opt,
1094 .print_fopt = u32_print_opt,
aba5acdf 1095};