]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/f_u32.c
new stuff from jamal.
[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>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <syslog.h>
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>
aba5acdf
SH
23
24#include "utils.h"
25#include "tc_util.h"
26
27static void explain(void)
28{
29 fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n");
30 fprintf(stderr, " [ police POLICE_SPEC ] [ offset OFFSET_SPEC ]\n");
31 fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
32 fprintf(stderr, " [ sample SAMPLE ]\n");
33 fprintf(stderr, "or u32 divisor DIVISOR\n");
34 fprintf(stderr, "\n");
35 fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
36 fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} } SAMPLE_ARGS\n");
37 fprintf(stderr, " FILTERID := X:Y:Z\n");
38}
39
40#define usage() return(-1)
41
42int get_u32_handle(__u32 *handle, char *str)
43{
44 __u32 htid=0, hash=0, nodeid=0;
45 char *tmp = strchr(str, ':');
46
47 if (tmp == NULL) {
48 if (memcmp("0x", str, 2) == 0)
49 return get_u32(handle, str, 16);
50 return -1;
51 }
52 htid = strtoul(str, &tmp, 16);
53 if (tmp == str && *str != ':' && *str != 0)
54 return -1;
55 if (htid>=0x1000)
56 return -1;
57 if (*tmp) {
58 str = tmp+1;
59 hash = strtoul(str, &tmp, 16);
60 if (tmp == str && *str != ':' && *str != 0)
61 return -1;
62 if (hash>=0x100)
63 return -1;
64 if (*tmp) {
65 str = tmp+1;
66 nodeid = strtoul(str, &tmp, 16);
67 if (tmp == str && *str != 0)
68 return -1;
69 if (nodeid>=0x1000)
70 return -1;
71 }
72 }
73 *handle = (htid<<20)|(hash<<12)|nodeid;
74 return 0;
75}
76
77char * sprint_u32_handle(__u32 handle, char *buf)
78{
79 int bsize = SPRINT_BSIZE-1;
80 __u32 htid = TC_U32_HTID(handle);
81 __u32 hash = TC_U32_HASH(handle);
82 __u32 nodeid = TC_U32_NODE(handle);
83 char *b = buf;
84
85 if (handle == 0) {
86 snprintf(b, bsize, "none");
87 return b;
88 }
89 if (htid) {
90 int l = snprintf(b, bsize, "%x:", htid>>20);
91 bsize -= l;
92 b += l;
93 }
94 if (nodeid|hash) {
95 if (hash) {
96 int l = snprintf(b, bsize, "%x", hash);
97 bsize -= l;
98 b += l;
99 }
100 if (nodeid) {
101 int l = snprintf(b, bsize, ":%x", nodeid);
102 bsize -= l;
103 b += l;
104 }
105 }
106 if (show_raw)
107 snprintf(b, bsize, "[%08x] ", handle);
108 return buf;
109}
110
111static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
112{
113 int i;
114 int hwm = sel->nkeys;
115
116 key &= mask;
117
118 for (i=0; i<hwm; i++) {
119 if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
120 __u32 intersect = mask&sel->keys[i].mask;
121
122 if ((key^sel->keys[i].val) & intersect)
123 return -1;
124 sel->keys[i].val |= key;
125 sel->keys[i].mask |= mask;
2373fde9
SH
126 sel->keys[i].off = 0;
127 sel->keys[i].offmask = 0;
aba5acdf
SH
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();
499 res = parse_u8(&argc, &argv, sel, 0, 0);
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
595
596
597static int parse_selector(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
598{
599 int argc = *argc_p;
600 char **argv = *argv_p;
601 int res = -1;
602
603 if (argc <= 0)
604 return -1;
605
606 if (matches(*argv, "u32") == 0) {
607 NEXT_ARG();
608 res = parse_u32(&argc, &argv, sel, 0, 0);
609 goto done;
610 }
611 if (matches(*argv, "u16") == 0) {
612 NEXT_ARG();
613 res = parse_u16(&argc, &argv, sel, 0, 0);
614 goto done;
615 }
616 if (matches(*argv, "u8") == 0) {
617 NEXT_ARG();
618 res = parse_u8(&argc, &argv, sel, 0, 0);
619 goto done;
620 }
621 if (matches(*argv, "ip") == 0) {
622 NEXT_ARG();
623 res = parse_ip(&argc, &argv, sel);
624 goto done;
625 }
626 if (matches(*argv, "ip6") == 0) {
627 NEXT_ARG();
628 res = parse_ip6(&argc, &argv, sel);
629 goto done;
630 }
631 if (matches(*argv, "udp") == 0) {
632 NEXT_ARG();
633 res = parse_udp(&argc, &argv, sel);
634 goto done;
635 }
636 if (matches(*argv, "tcp") == 0) {
637 NEXT_ARG();
638 res = parse_tcp(&argc, &argv, sel);
639 goto done;
640 }
641 if (matches(*argv, "icmp") == 0) {
642 NEXT_ARG();
643 res = parse_icmp(&argc, &argv, sel);
644 goto done;
645 }
646 return -1;
647
648done:
649 *argc_p = argc;
650 *argv_p = argv;
651 return res;
652}
653
654static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
655{
656 int argc = *argc_p;
657 char **argv = *argv_p;
658
659 while (argc > 0) {
660 if (matches(*argv, "plus") == 0) {
661 int off;
662 NEXT_ARG();
663 if (get_integer(&off, *argv, 0))
664 return -1;
665 sel->off = off;
666 sel->flags |= TC_U32_OFFSET;
667 } else if (matches(*argv, "at") == 0) {
668 int off;
669 NEXT_ARG();
670 if (get_integer(&off, *argv, 0))
671 return -1;
672 sel->offoff = off;
673 if (off%2) {
674 fprintf(stderr, "offset \"at\" must be even\n");
675 return -1;
676 }
677 sel->flags |= TC_U32_VAROFFSET;
678 } else if (matches(*argv, "mask") == 0) {
679 __u16 mask;
680 NEXT_ARG();
681 if (get_u16(&mask, *argv, 16))
682 return -1;
683 sel->offmask = htons(mask);
684 sel->flags |= TC_U32_VAROFFSET;
685 } else if (matches(*argv, "shift") == 0) {
686 int shift;
687 NEXT_ARG();
688 if (get_integer(&shift, *argv, 0))
689 return -1;
690 sel->offshift = shift;
691 sel->flags |= TC_U32_VAROFFSET;
692 } else if (matches(*argv, "eat") == 0) {
693 sel->flags |= TC_U32_EAT;
694 } else {
695 break;
696 }
697 argc--; argv++;
698 }
699
700 *argc_p = argc;
701 *argv_p = argv;
702 return 0;
703}
704
705static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
706{
707 int argc = *argc_p;
708 char **argv = *argv_p;
709
710 while (argc > 0) {
711 if (matches(*argv, "mask") == 0) {
712 __u32 mask;
2373fde9 713 int i = 0;
aba5acdf
SH
714 NEXT_ARG();
715 if (get_u32(&mask, *argv, 16))
716 return -1;
717 sel->hmask = htonl(mask);
2373fde9
SH
718 mask = sel->hmask;
719 while (!(mask & 1)) {
720 i++;
721 mask>>=1;
722 }
723#ifdef fix_u32_bug
724 sel->fshift = i;
725#endif
aba5acdf
SH
726 } else if (matches(*argv, "at") == 0) {
727 int num;
728 NEXT_ARG();
729 if (get_integer(&num, *argv, 0))
730 return -1;
731 if (num%4)
732 return -1;
733 sel->hoff = num;
734 } else {
735 break;
736 }
737 argc--; argv++;
738 }
739
740 *argc_p = argc;
741 *argv_p = argv;
742 return 0;
743}
744
745static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)
746{
747 struct {
748 struct tc_u32_sel sel;
749 struct tc_u32_key keys[128];
750 } sel;
751 struct tcmsg *t = NLMSG_DATA(n);
752 struct rtattr *tail;
753 int sel_ok = 0;
754 int sample_ok = 0;
755 __u32 htid = 0;
756 __u32 order = 0;
757
758 memset(&sel, 0, sizeof(sel));
759
760 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
761 fprintf(stderr, "Illegal filter ID\n");
762 return -1;
763 }
764
765 if (argc == 0)
766 return 0;
767
768 tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len));
2373fde9 769 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
aba5acdf
SH
770
771 while (argc > 0) {
772 if (matches(*argv, "match") == 0) {
773 NEXT_ARG();
774 if (parse_selector(&argc, &argv, &sel.sel)) {
775 fprintf(stderr, "Illegal \"match\"\n");
776 return -1;
777 }
778 sel_ok++;
779 continue;
780 } else if (matches(*argv, "offset") == 0) {
781 NEXT_ARG();
782 if (parse_offset(&argc, &argv, &sel.sel)) {
783 fprintf(stderr, "Illegal \"offset\"\n");
784 return -1;
785 }
786 continue;
787 } else if (matches(*argv, "hashkey") == 0) {
788 NEXT_ARG();
789 if (parse_hashkey(&argc, &argv, &sel.sel)) {
790 fprintf(stderr, "Illegal \"hashkey\"\n");
791 return -1;
792 }
793 continue;
794 } else if (matches(*argv, "classid") == 0 ||
795 strcmp(*argv, "flowid") == 0) {
796 unsigned handle;
797 NEXT_ARG();
798 if (get_tc_classid(&handle, *argv)) {
799 fprintf(stderr, "Illegal \"classid\"\n");
800 return -1;
801 }
2373fde9 802 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4);
aba5acdf
SH
803 sel.sel.flags |= TC_U32_TERMINAL;
804 } else if (matches(*argv, "divisor") == 0) {
805 unsigned divisor;
806 NEXT_ARG();
807 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
808 divisor > 0x100) {
809 fprintf(stderr, "Illegal \"divisor\"\n");
810 return -1;
811 }
2373fde9 812 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
aba5acdf
SH
813 } else if (matches(*argv, "order") == 0) {
814 NEXT_ARG();
815 if (get_u32(&order, *argv, 0)) {
816 fprintf(stderr, "Illegal \"order\"\n");
817 return -1;
818 }
819 } else if (strcmp(*argv, "link") == 0) {
820 unsigned handle;
821 NEXT_ARG();
822 if (get_u32_handle(&handle, *argv)) {
823 fprintf(stderr, "Illegal \"link\"\n");
824 return -1;
825 }
826 if (handle && TC_U32_NODE(handle)) {
827 fprintf(stderr, "\"link\" must be a hash table.\n");
828 return -1;
829 }
2373fde9 830 addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4);
aba5acdf
SH
831 } else if (strcmp(*argv, "ht") == 0) {
832 unsigned handle;
833 NEXT_ARG();
834 if (get_u32_handle(&handle, *argv)) {
835 fprintf(stderr, "Illegal \"ht\"\n");
836 return -1;
837 }
838 if (handle && TC_U32_NODE(handle)) {
839 fprintf(stderr, "\"ht\" must be a hash table.\n");
840 return -1;
841 }
842 if (sample_ok)
843 htid = (htid&0xFF000)|(handle&0xFFF00000);
844 else
845 htid = (handle&0xFFFFF000);
846 } else if (strcmp(*argv, "sample") == 0) {
847 __u32 hash;
848 struct {
849 struct tc_u32_sel sel;
850 struct tc_u32_key keys[4];
851 } sel2;
852 NEXT_ARG();
853 if (parse_selector(&argc, &argv, &sel2.sel)) {
854 fprintf(stderr, "Illegal \"sample\"\n");
855 return -1;
856 }
857 if (sel2.sel.nkeys != 1) {
858 fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
859 return -1;
860 }
861 hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask;
862 hash ^= hash>>16;
863 hash ^= hash>>8;
864 htid = ((hash<<12)&0xFF000)|(htid&0xFFF00000);
865 sample_ok = 1;
866 continue;
2373fde9
SH
867 } else if (strcmp(*argv, "indev") == 0) {
868 char ind[IFNAMSIZ + 1];
869 memset(ind, 0, sizeof (ind));
870 argc--;
871 argv++;
872 if (argc < 1) {
873 fprintf(stderr, "Illegal indev\n");
874 return -1;
875 }
876 strncpy(ind, *argv, sizeof (ind) - 1);
877 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1);
878 } else if (matches(*argv, "action") == 0) {
879 NEXT_ARG();
880 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
881 fprintf(stderr, "Illegal \"action\"\n");
882 return -1;
883 }
884 continue;
aba5acdf
SH
885 } else if (matches(*argv, "police") == 0) {
886 NEXT_ARG();
887 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
888 fprintf(stderr, "Illegal \"police\"\n");
889 return -1;
890 }
891 continue;
892 } else if (strcmp(*argv, "help") == 0) {
893 explain();
894 return -1;
895 } else {
896 fprintf(stderr, "What is \"%s\"?\n", *argv);
897 explain();
898 return -1;
899 }
900 argc--; argv++;
901 }
902
903 if (order) {
904 if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
905 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
906 return -1;
907 }
908 t->tcm_handle |= order;
909 }
910
911 if (htid)
2373fde9 912 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
aba5acdf 913 if (sel_ok)
2373fde9 914 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
aba5acdf
SH
915 tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail;
916 return 0;
917}
918
919static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle)
920{
921 struct rtattr *tb[TCA_U32_MAX+1];
922 struct tc_u32_sel *sel = NULL;
923
924 if (opt == NULL)
925 return 0;
926
927 memset(tb, 0, sizeof(tb));
928 if (opt)
929 parse_rtattr(tb, TCA_U32_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt));
930
931 if (handle) {
932 SPRINT_BUF(b1);
933 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
934 }
935 if (TC_U32_NODE(handle)) {
936 fprintf(f, "order %d ", TC_U32_NODE(handle));
937 }
938
939 if (tb[TCA_U32_SEL]) {
940 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
941 return -1;
942
943 sel = RTA_DATA(tb[TCA_U32_SEL]);
944 }
945
946 if (tb[TCA_U32_DIVISOR]) {
947 fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR]));
948 } else if (tb[TCA_U32_HASH]) {
949 __u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]);
950 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid), TC_U32_HASH(htid));
951 } else {
952 fprintf(f, "??? ");
953 }
954 if (tb[TCA_U32_CLASSID]) {
955 SPRINT_BUF(b1);
956 fprintf(f, "%sflowid %s ",
957 !sel || !(sel->flags&TC_U32_TERMINAL) ? "*" : "",
958 sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_U32_CLASSID]), b1));
959 } else if (sel && sel->flags&TC_U32_TERMINAL) {
960 fprintf(f, "terminal flowid ??? ");
961 }
962 if (tb[TCA_U32_LINK]) {
963 SPRINT_BUF(b1);
964 fprintf(f, "link %s ", sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
965 }
2373fde9 966
aba5acdf
SH
967
968 if (sel) {
969 int i;
970 struct tc_u32_key *key = sel->keys;
aba5acdf 971 if (sel->nkeys) {
2373fde9 972 for (i=0; i<sel->nkeys; i++, key++) {
aba5acdf
SH
973 fprintf(f, "\n match %08x/%08x at %s%d",
974 (unsigned int)ntohl(key->val),
975 (unsigned int)ntohl(key->mask),
976 key->offmask ? "nexthdr+" : "",
977 key->off);
2373fde9 978 }
aba5acdf
SH
979 }
980
981 if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) {
982 fprintf(f, "\n offset ");
983 if (sel->flags&TC_U32_VAROFFSET)
984 fprintf(f, "%04x>>%d at %d ", ntohs(sel->offmask), sel->offshift, sel->offoff);
985 if (sel->off)
986 fprintf(f, "plus %d ", sel->off);
987 }
988 if (sel->flags&TC_U32_EAT)
989 fprintf(f, " eat ");
990
991 if (sel->hmask) {
992 fprintf(f, "\n hash mask %08x at %d ",
993 (unsigned int)htonl(sel->hmask), sel->hoff);
994 }
995 }
996
2373fde9
SH
997 if (show_stats && tb[TCA_U32_PCNT]){
998 struct tc_u32_pcnt *p = RTA_DATA(tb[TCA_U32_PCNT]);
999 fprintf(f, " (rule hit %llu success %llu)",
1000 p->rcnt, p->rhit);
1001 }
1002 if (tb[TCA_U32_POLICE]) {
1003 fprintf(f, "\n");
1004 tc_print_police(f, tb[TCA_U32_POLICE]);
1005 }
1006 if (tb[TCA_U32_INDEV]) {
1007 struct rtattr *idev = tb[TCA_U32_INDEV];
1008 fprintf(f, "\n input dev %s\n", (char *) RTA_DATA(idev));
1009 }
1010 if (tb[TCA_U32_ACT]) {
1011 tc_print_action(f, tb[TCA_U32_ACT]);
1012 }
1013
aba5acdf
SH
1014 return 0;
1015}
1016
1017struct filter_util u32_util = {
1018 NULL,
1019 "u32",
1020 u32_parse_opt,
1021 u32_print_opt,
1022};