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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 * Match mark added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> [5 nov 2004]
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
23 #include <linux/if_ether.h>
28 static void explain(void)
31 "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"
32 " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"
33 " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"
34 " [ sample SAMPLE ] [skip_hw | skip_sw]\n"
35 "or u32 divisor DIVISOR\n"
37 "Where: SELECTOR := SAMPLE SAMPLE ...\n"
38 " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n"
39 " SAMPLE_ARGS [ divisor DIVISOR ]\n"
40 " FILTERID := X:Y:Z\n"
41 "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
44 static int get_u32_handle(__u32
*handle
, const char *str
)
46 __u32 htid
= 0, hash
= 0, nodeid
= 0;
47 char *tmp
= strchr(str
, ':');
50 if (memcmp("0x", str
, 2) == 0)
51 return get_u32(handle
, str
, 16);
54 htid
= strtoul(str
, &tmp
, 16);
55 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
61 hash
= strtoul(str
, &tmp
, 16);
62 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
68 nodeid
= strtoul(str
, &tmp
, 16);
69 if (tmp
== str
&& *str
!= 0)
75 *handle
= (htid
<<20)|(hash
<<12)|nodeid
;
79 static char *sprint_u32_handle(__u32 handle
, char *buf
)
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
);
88 snprintf(b
, bsize
, "none");
92 int l
= snprintf(b
, bsize
, "%x:", htid
>>20);
99 int l
= snprintf(b
, bsize
, "%x", hash
);
105 int l
= snprintf(b
, bsize
, ":%x", nodeid
);
112 snprintf(b
, bsize
, "[%08x] ", handle
);
116 static int pack_key(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
117 int off
, int offmask
)
120 int hwm
= sel
->nkeys
;
124 for (i
= 0; i
< hwm
; i
++) {
125 if (sel
->keys
[i
].off
== off
&& sel
->keys
[i
].offmask
== offmask
) {
126 __u32 intersect
= mask
& sel
->keys
[i
].mask
;
128 if ((key
^ sel
->keys
[i
].val
) & intersect
)
130 sel
->keys
[i
].val
|= key
;
131 sel
->keys
[i
].mask
|= mask
;
140 sel
->keys
[hwm
].val
= key
;
141 sel
->keys
[hwm
].mask
= mask
;
142 sel
->keys
[hwm
].off
= off
;
143 sel
->keys
[hwm
].offmask
= offmask
;
148 static int pack_key32(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
149 int off
, int offmask
)
153 return pack_key(sel
, key
, mask
, off
, offmask
);
156 static int pack_key16(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
157 int off
, int offmask
)
159 if (key
> 0xFFFF || mask
> 0xFFFF)
162 if ((off
& 3) == 0) {
170 return pack_key(sel
, key
, mask
, off
, offmask
);
173 static int pack_key8(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
,
176 if (key
> 0xFF || mask
> 0xFF)
179 if ((off
& 3) == 0) {
182 } else if ((off
& 3) == 1) {
185 } else if ((off
& 3) == 2) {
193 return pack_key(sel
, key
, mask
, off
, offmask
);
197 static int parse_at(int *argc_p
, char ***argv_p
, int *off
, int *offmask
)
200 char **argv
= *argv_p
;
206 if (strlen(p
) > strlen("nexthdr+") &&
207 memcmp(p
, "nexthdr+", strlen("nexthdr+")) == 0) {
209 p
+= strlen("nexthdr+");
210 } else if (matches(*argv
, "nexthdr+") == 0) {
216 if (get_integer(off
, p
, 0))
226 static int parse_u32(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
227 int off
, int offmask
)
231 char **argv
= *argv_p
;
238 if (get_u32(&key
, *argv
, 0))
242 if (get_u32(&mask
, *argv
, 16))
246 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
248 if (parse_at(&argc
, &argv
, &off
, &offmask
))
252 res
= pack_key32(sel
, key
, mask
, off
, offmask
);
258 static int parse_u16(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
259 int off
, int offmask
)
263 char **argv
= *argv_p
;
270 if (get_u32(&key
, *argv
, 0))
274 if (get_u32(&mask
, *argv
, 16))
278 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
280 if (parse_at(&argc
, &argv
, &off
, &offmask
))
283 res
= pack_key16(sel
, key
, mask
, off
, offmask
);
289 static int parse_u8(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
290 int off
, int offmask
)
294 char **argv
= *argv_p
;
301 if (get_u32(&key
, *argv
, 0))
305 if (get_u32(&mask
, *argv
, 16))
309 if (key
> 0xFF || mask
> 0xFF)
312 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
314 if (parse_at(&argc
, &argv
, &off
, &offmask
))
318 res
= pack_key8(sel
, key
, mask
, off
, offmask
);
324 static int parse_ip_addr(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
329 char **argv
= *argv_p
;
337 if (get_prefix_1(&addr
, *argv
, AF_INET
))
341 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
343 if (parse_at(&argc
, &argv
, &off
, &offmask
))
349 mask
= htonl(0xFFFFFFFF << (32 - addr
.bitlen
));
350 if (pack_key(sel
, addr
.data
[0], mask
, off
, offmask
) < 0)
359 static int parse_ip6_addr(int *argc_p
, char ***argv_p
,
360 struct tc_u32_sel
*sel
, int off
)
364 char **argv
= *argv_p
;
373 if (get_prefix_1(&addr
, *argv
, AF_INET6
))
377 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
379 if (parse_at(&argc
, &argv
, &off
, &offmask
))
384 for (i
= 0; i
< plen
; i
+= 32) {
386 res
= pack_key(sel
, addr
.data
[i
/ 32],
387 0xFFFFFFFF, off
+ 4 * (i
/ 32), offmask
);
390 } else if (i
< plen
) {
391 __u32 mask
= htonl(0xFFFFFFFF << (32 - (plen
- i
)));
393 res
= pack_key(sel
, addr
.data
[i
/ 32],
394 mask
, off
+ 4 * (i
/ 32), offmask
);
406 static int parse_ip6_class(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
410 char **argv
= *argv_p
;
419 if (get_u32(&key
, *argv
, 0))
423 if (get_u32(&mask
, *argv
, 16))
427 if (key
> 0xFF || mask
> 0xFF)
435 res
= pack_key(sel
, key
, mask
, off
, offmask
);
444 static int parse_ether_addr(int *argc_p
, char ***argv_p
,
445 struct tc_u32_sel
*sel
, int off
)
449 char **argv
= *argv_p
;
457 if (sscanf(*argv
, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
458 addr
+ 0, addr
+ 1, addr
+ 2,
459 addr
+ 3, addr
+ 4, addr
+ 5) != 6) {
460 fprintf(stderr
, "parse_ether_addr: improperly formed address '%s'\n",
466 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
468 if (parse_at(&argc
, &argv
, &off
, &offmask
))
472 for (i
= 0; i
< 6; i
++) {
473 res
= pack_key8(sel
, addr
[i
], 0xFF, off
+ i
, offmask
);
483 static int parse_ip(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
487 char **argv
= *argv_p
;
492 if (strcmp(*argv
, "src") == 0) {
494 res
= parse_ip_addr(&argc
, &argv
, sel
, 12);
495 } else if (strcmp(*argv
, "dst") == 0) {
497 res
= parse_ip_addr(&argc
, &argv
, sel
, 16);
498 } else if (strcmp(*argv
, "tos") == 0 ||
499 matches(*argv
, "dsfield") == 0 ||
500 matches(*argv
, "precedence") == 0) {
502 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
503 } else if (strcmp(*argv
, "ihl") == 0) {
505 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
506 } else if (strcmp(*argv
, "protocol") == 0) {
508 res
= parse_u8(&argc
, &argv
, sel
, 9, 0);
509 } else if (strcmp(*argv
, "nofrag") == 0) {
511 res
= pack_key16(sel
, 0, 0x3FFF, 6, 0);
512 } else if (strcmp(*argv
, "firstfrag") == 0) {
514 res
= pack_key16(sel
, 0x2000, 0x3FFF, 6, 0);
515 } else if (strcmp(*argv
, "df") == 0) {
517 res
= pack_key16(sel
, 0x4000, 0x4000, 6, 0);
518 } else if (strcmp(*argv
, "mf") == 0) {
520 res
= pack_key16(sel
, 0x2000, 0x2000, 6, 0);
521 } else if (strcmp(*argv
, "dport") == 0) {
523 res
= parse_u16(&argc
, &argv
, sel
, 22, 0);
524 } else if (strcmp(*argv
, "sport") == 0) {
526 res
= parse_u16(&argc
, &argv
, sel
, 20, 0);
527 } else if (strcmp(*argv
, "icmp_type") == 0) {
529 res
= parse_u8(&argc
, &argv
, sel
, 20, 0);
530 } else if (strcmp(*argv
, "icmp_code") == 0) {
532 res
= parse_u8(&argc
, &argv
, sel
, 21, 0);
541 static int parse_ip6(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
545 char **argv
= *argv_p
;
550 if (strcmp(*argv
, "src") == 0) {
552 res
= parse_ip6_addr(&argc
, &argv
, sel
, 8);
553 } else if (strcmp(*argv
, "dst") == 0) {
555 res
= parse_ip6_addr(&argc
, &argv
, sel
, 24);
556 } else if (strcmp(*argv
, "priority") == 0) {
558 res
= parse_ip6_class(&argc
, &argv
, sel
);
559 } else if (strcmp(*argv
, "protocol") == 0) {
561 res
= parse_u8(&argc
, &argv
, sel
, 6, 0);
562 } else if (strcmp(*argv
, "flowlabel") == 0) {
564 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
565 } else if (strcmp(*argv
, "dport") == 0) {
567 res
= parse_u16(&argc
, &argv
, sel
, 42, 0);
568 } else if (strcmp(*argv
, "sport") == 0) {
570 res
= parse_u16(&argc
, &argv
, sel
, 40, 0);
571 } else if (strcmp(*argv
, "icmp_type") == 0) {
573 res
= parse_u8(&argc
, &argv
, sel
, 40, 0);
574 } else if (strcmp(*argv
, "icmp_code") == 0) {
576 res
= parse_u8(&argc
, &argv
, sel
, 41, 1);
585 static int parse_ether(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
589 char **argv
= *argv_p
;
594 if (strcmp(*argv
, "src") == 0) {
596 res
= parse_ether_addr(&argc
, &argv
, sel
, -8);
597 } else if (strcmp(*argv
, "dst") == 0) {
599 res
= parse_ether_addr(&argc
, &argv
, sel
, -14);
601 fprintf(stderr
, "Unknown match: ether %s\n", *argv
);
610 #define parse_tcp parse_udp
611 static int parse_udp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
615 char **argv
= *argv_p
;
620 if (strcmp(*argv
, "src") == 0) {
622 res
= parse_u16(&argc
, &argv
, sel
, 0, -1);
623 } else if (strcmp(*argv
, "dst") == 0) {
625 res
= parse_u16(&argc
, &argv
, sel
, 2, -1);
635 static int parse_icmp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
639 char **argv
= *argv_p
;
644 if (strcmp(*argv
, "type") == 0) {
646 res
= parse_u8(&argc
, &argv
, sel
, 0, -1);
647 } else if (strcmp(*argv
, "code") == 0) {
649 res
= parse_u8(&argc
, &argv
, sel
, 1, -1);
658 static int parse_mark(int *argc_p
, char ***argv_p
, struct nlmsghdr
*n
)
662 char **argv
= *argv_p
;
663 struct tc_u32_mark mark
;
668 if (get_u32(&mark
.val
, *argv
, 0)) {
669 fprintf(stderr
, "Illegal \"mark\" value\n");
674 if (get_u32(&mark
.mask
, *argv
, 0)) {
675 fprintf(stderr
, "Illegal \"mark\" mask\n");
680 if ((mark
.val
& mark
.mask
) != mark
.val
) {
681 fprintf(stderr
, "Illegal \"mark\" (impossible combination)\n");
685 addattr_l(n
, MAX_MSG
, TCA_U32_MARK
, &mark
, sizeof(mark
));
693 static int parse_selector(int *argc_p
, char ***argv_p
,
694 struct tc_u32_sel
*sel
, struct nlmsghdr
*n
)
697 char **argv
= *argv_p
;
703 if (matches(*argv
, "u32") == 0) {
705 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
706 } else if (matches(*argv
, "u16") == 0) {
708 res
= parse_u16(&argc
, &argv
, sel
, 0, 0);
709 } else if (matches(*argv
, "u8") == 0) {
711 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
712 } else if (matches(*argv
, "ip") == 0) {
714 res
= parse_ip(&argc
, &argv
, sel
);
715 } else if (matches(*argv
, "ip6") == 0) {
717 res
= parse_ip6(&argc
, &argv
, sel
);
718 } else if (matches(*argv
, "udp") == 0) {
720 res
= parse_udp(&argc
, &argv
, sel
);
721 } else if (matches(*argv
, "tcp") == 0) {
723 res
= parse_tcp(&argc
, &argv
, sel
);
724 } else if (matches(*argv
, "icmp") == 0) {
726 res
= parse_icmp(&argc
, &argv
, sel
);
727 } else if (matches(*argv
, "mark") == 0) {
729 res
= parse_mark(&argc
, &argv
, n
);
730 } else if (matches(*argv
, "ether") == 0) {
732 res
= parse_ether(&argc
, &argv
, sel
);
741 static int parse_offset(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
744 char **argv
= *argv_p
;
747 if (matches(*argv
, "plus") == 0) {
751 if (get_integer(&off
, *argv
, 0))
754 sel
->flags
|= TC_U32_OFFSET
;
755 } else if (matches(*argv
, "at") == 0) {
759 if (get_integer(&off
, *argv
, 0))
763 fprintf(stderr
, "offset \"at\" must be even\n");
766 sel
->flags
|= TC_U32_VAROFFSET
;
767 } else if (matches(*argv
, "mask") == 0) {
769 if (get_be16(&sel
->offmask
, *argv
, 16))
771 sel
->flags
|= TC_U32_VAROFFSET
;
772 } else if (matches(*argv
, "shift") == 0) {
776 if (get_integer(&shift
, *argv
, 0))
778 sel
->offshift
= shift
;
779 sel
->flags
|= TC_U32_VAROFFSET
;
780 } else if (matches(*argv
, "eat") == 0) {
781 sel
->flags
|= TC_U32_EAT
;
793 static int parse_hashkey(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
796 char **argv
= *argv_p
;
799 if (matches(*argv
, "mask") == 0) {
801 if (get_be32(&sel
->hmask
, *argv
, 16))
803 } else if (matches(*argv
, "at") == 0) {
807 if (get_integer(&num
, *argv
, 0))
823 static void print_ipv4(FILE *f
, const struct tc_u32_key
*key
)
829 switch (ntohl(key
->mask
)) {
831 fprintf(f
, "\n match IP ihl %u",
832 ntohl(key
->val
) >> 24);
835 fprintf(f
, "\n match IP dsfield %#x",
836 ntohl(key
->val
) >> 16);
841 if (ntohl(key
->mask
) == 0x00ff0000) {
842 fprintf(f
, "\n match IP protocol %d",
843 ntohl(key
->val
) >> 16);
849 int bits
= mask2bits(key
->mask
);
852 fprintf(f
, "\n %s %s/%d",
853 key
->off
== 12 ? "match IP src" : "match IP dst",
854 inet_ntop(AF_INET
, &key
->val
,
863 switch (ntohl(key
->mask
)) {
865 fprintf(f
, "\n match dport %u",
866 ntohl(key
->val
) & 0xffff);
869 fprintf(f
, "\n match sport %u",
870 ntohl(key
->val
) >> 16);
873 fprintf(f
, "\n match dport %u, match sport %u",
874 ntohl(key
->val
) & 0xffff,
875 ntohl(key
->val
) >> 16);
879 /* XXX: Default print_raw */
883 static void print_ipv6(FILE *f
, const struct tc_u32_key
*key
)
889 switch (ntohl(key
->mask
)) {
891 fprintf(f
, "\n match IP ihl %u",
892 ntohl(key
->val
) >> 24);
895 fprintf(f
, "\n match IP dsfield %#x",
896 ntohl(key
->val
) >> 16);
901 if (ntohl(key
->mask
) == 0x00ff0000) {
902 fprintf(f
, "\n match IP protocol %d",
903 ntohl(key
->val
) >> 16);
909 int bits
= mask2bits(key
->mask
);
912 fprintf(f
, "\n %s %s/%d",
913 key
->off
== 12 ? "match IP src" : "match IP dst",
914 inet_ntop(AF_INET
, &key
->val
,
923 switch (ntohl(key
->mask
)) {
925 fprintf(f
, "\n match sport %u",
926 ntohl(key
->val
) & 0xffff);
929 fprintf(f
, "\n match dport %u",
930 ntohl(key
->val
) >> 16);
933 fprintf(f
, "\n match sport %u, match dport %u",
934 ntohl(key
->val
) & 0xffff,
935 ntohl(key
->val
) >> 16);
939 /* XXX: Default print_raw */
943 static void print_raw(FILE *f
, const struct tc_u32_key
*key
)
945 fprintf(f
, "\n match %08x/%08x at %s%d",
946 (unsigned int)ntohl(key
->val
),
947 (unsigned int)ntohl(key
->mask
),
948 key
->offmask
? "nexthdr+" : "",
952 static const struct {
955 void (*pprinter
)(FILE *f
, const struct tc_u32_key
*key
);
956 } u32_pprinters
[] = {
958 {ETH_P_IP
, 0, print_ipv4
},
959 {ETH_P_IPV6
, 0, print_ipv6
},
962 static void show_keys(FILE *f
, const struct tc_u32_key
*key
)
969 for (i
= 0; i
< ARRAY_SIZE(u32_pprinters
); i
++) {
970 if (u32_pprinters
[i
].proto
== ntohs(f_proto
)) {
972 u32_pprinters
[i
].pprinter(f
, key
);
981 static int u32_parse_opt(struct filter_util
*qu
, char *handle
,
982 int argc
, char **argv
, struct nlmsghdr
*n
)
985 struct tc_u32_sel sel
;
986 struct tc_u32_key keys
[128];
988 struct tcmsg
*t
= NLMSG_DATA(n
);
990 int sel_ok
= 0, terminal_ok
= 0;
996 if (handle
&& get_u32_handle(&t
->tcm_handle
, handle
)) {
997 fprintf(stderr
, "Illegal filter ID\n");
1004 tail
= addattr_nest(n
, MAX_MSG
, TCA_OPTIONS
);
1007 if (matches(*argv
, "match") == 0) {
1009 if (parse_selector(&argc
, &argv
, &sel
.sel
, n
)) {
1010 fprintf(stderr
, "Illegal \"match\"\n");
1015 } else if (matches(*argv
, "offset") == 0) {
1017 if (parse_offset(&argc
, &argv
, &sel
.sel
)) {
1018 fprintf(stderr
, "Illegal \"offset\"\n");
1022 } else if (matches(*argv
, "hashkey") == 0) {
1024 if (parse_hashkey(&argc
, &argv
, &sel
.sel
)) {
1025 fprintf(stderr
, "Illegal \"hashkey\"\n");
1029 } else if (matches(*argv
, "classid") == 0 ||
1030 strcmp(*argv
, "flowid") == 0) {
1031 unsigned int flowid
;
1034 if (get_tc_classid(&flowid
, *argv
)) {
1035 fprintf(stderr
, "Illegal \"classid\"\n");
1038 addattr_l(n
, MAX_MSG
, TCA_U32_CLASSID
, &flowid
, 4);
1039 sel
.sel
.flags
|= TC_U32_TERMINAL
;
1040 } else if (matches(*argv
, "divisor") == 0) {
1041 unsigned int divisor
;
1044 if (get_unsigned(&divisor
, *argv
, 0) ||
1046 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
1047 fprintf(stderr
, "Illegal \"divisor\"\n");
1050 addattr_l(n
, MAX_MSG
, TCA_U32_DIVISOR
, &divisor
, 4);
1051 } else if (matches(*argv
, "order") == 0) {
1053 if (get_u32(&order
, *argv
, 0)) {
1054 fprintf(stderr
, "Illegal \"order\"\n");
1057 } else if (strcmp(*argv
, "link") == 0) {
1058 unsigned int linkid
;
1061 if (get_u32_handle(&linkid
, *argv
)) {
1062 fprintf(stderr
, "Illegal \"link\"\n");
1065 if (linkid
&& TC_U32_NODE(linkid
)) {
1066 fprintf(stderr
, "\"link\" must be a hash table.\n");
1069 addattr_l(n
, MAX_MSG
, TCA_U32_LINK
, &linkid
, 4);
1070 } else if (strcmp(*argv
, "ht") == 0) {
1074 if (get_u32_handle(&ht
, *argv
)) {
1075 fprintf(stderr
, "Illegal \"ht\"\n");
1078 if (handle
&& TC_U32_NODE(ht
)) {
1079 fprintf(stderr
, "\"ht\" must be a hash table.\n");
1083 htid
= (htid
& 0xFF000) | (ht
& 0xFFF00000);
1085 htid
= (ht
& 0xFFFFF000);
1086 } else if (strcmp(*argv
, "sample") == 0) {
1088 unsigned int divisor
= 0x100;
1090 struct tc_u32_sel sel
;
1091 struct tc_u32_key keys
[4];
1095 if (parse_selector(&argc
, &argv
, &sel2
.sel
, n
)) {
1096 fprintf(stderr
, "Illegal \"sample\"\n");
1099 if (sel2
.sel
.nkeys
!= 1) {
1100 fprintf(stderr
, "\"sample\" must contain exactly ONE key.\n");
1103 if (*argv
!= 0 && strcmp(*argv
, "divisor") == 0) {
1105 if (get_unsigned(&divisor
, *argv
, 0) ||
1106 divisor
== 0 || divisor
> 0x100 ||
1107 ((divisor
- 1) & divisor
)) {
1108 fprintf(stderr
, "Illegal sample \"divisor\"\n");
1113 hash
= sel2
.sel
.keys
[0].val
& sel2
.sel
.keys
[0].mask
;
1116 htid
= ((hash
% divisor
) << 12) | (htid
& 0xFFF00000);
1119 } else if (strcmp(*argv
, "indev") == 0) {
1120 char ind
[IFNAMSIZ
+ 1] = {};
1125 fprintf(stderr
, "Illegal indev\n");
1128 strncpy(ind
, *argv
, sizeof(ind
) - 1);
1129 addattr_l(n
, MAX_MSG
, TCA_U32_INDEV
, ind
,
1132 } else if (matches(*argv
, "action") == 0) {
1134 if (parse_action(&argc
, &argv
, TCA_U32_ACT
, n
)) {
1135 fprintf(stderr
, "Illegal \"action\"\n");
1141 } else if (matches(*argv
, "police") == 0) {
1143 if (parse_police(&argc
, &argv
, TCA_U32_POLICE
, n
)) {
1144 fprintf(stderr
, "Illegal \"police\"\n");
1149 } else if (strcmp(*argv
, "skip_hw") == 0) {
1150 flags
|= TCA_CLS_FLAGS_SKIP_HW
;
1151 } else if (strcmp(*argv
, "skip_sw") == 0) {
1152 flags
|= TCA_CLS_FLAGS_SKIP_SW
;
1153 } else if (strcmp(*argv
, "help") == 0) {
1157 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
1164 /* We don't necessarily need class/flowids */
1166 sel
.sel
.flags
|= TC_U32_TERMINAL
;
1169 if (TC_U32_NODE(t
->tcm_handle
) &&
1170 order
!= TC_U32_NODE(t
->tcm_handle
)) {
1171 fprintf(stderr
, "\"order\" contradicts \"handle\"\n");
1174 t
->tcm_handle
|= order
;
1178 addattr_l(n
, MAX_MSG
, TCA_U32_HASH
, &htid
, 4);
1180 addattr_l(n
, MAX_MSG
, TCA_U32_SEL
, &sel
,
1182 sel
.sel
.nkeys
* sizeof(struct tc_u32_key
));
1184 if (!(flags
^ (TCA_CLS_FLAGS_SKIP_HW
|
1185 TCA_CLS_FLAGS_SKIP_SW
))) {
1187 "skip_hw and skip_sw are mutually exclusive\n");
1190 addattr_l(n
, MAX_MSG
, TCA_U32_FLAGS
, &flags
, 4);
1193 addattr_nest_end(n
, tail
);
1197 static int u32_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
,
1200 struct rtattr
*tb
[TCA_U32_MAX
+ 1];
1201 struct tc_u32_sel
*sel
= NULL
;
1202 struct tc_u32_pcnt
*pf
= NULL
;
1207 parse_rtattr_nested(tb
, TCA_U32_MAX
, opt
);
1211 fprintf(f
, "fh %s ", sprint_u32_handle(handle
, b1
));
1214 if (TC_U32_NODE(handle
))
1215 fprintf(f
, "order %d ", TC_U32_NODE(handle
));
1217 if (tb
[TCA_U32_SEL
]) {
1218 if (RTA_PAYLOAD(tb
[TCA_U32_SEL
]) < sizeof(*sel
))
1221 sel
= RTA_DATA(tb
[TCA_U32_SEL
]);
1224 if (tb
[TCA_U32_DIVISOR
]) {
1225 fprintf(f
, "ht divisor %d ",
1226 rta_getattr_u32(tb
[TCA_U32_DIVISOR
]));
1227 } else if (tb
[TCA_U32_HASH
]) {
1228 __u32 htid
= rta_getattr_u32(tb
[TCA_U32_HASH
]);
1230 fprintf(f
, "key ht %x bkt %x ", TC_U32_USERHTID(htid
),
1235 if (tb
[TCA_U32_CLASSID
]) {
1237 fprintf(f
, "%sflowid %s ",
1238 !sel
|| !(sel
->flags
& TC_U32_TERMINAL
) ? "*" : "",
1239 sprint_tc_classid(rta_getattr_u32(tb
[TCA_U32_CLASSID
]),
1241 } else if (sel
&& sel
->flags
& TC_U32_TERMINAL
) {
1242 fprintf(f
, "terminal flowid ??? ");
1244 if (tb
[TCA_U32_LINK
]) {
1246 fprintf(f
, "link %s ",
1247 sprint_u32_handle(rta_getattr_u32(tb
[TCA_U32_LINK
]),
1251 if (tb
[TCA_U32_FLAGS
]) {
1252 __u32 flags
= rta_getattr_u32(tb
[TCA_U32_FLAGS
]);
1254 if (flags
& TCA_CLS_FLAGS_SKIP_HW
)
1255 fprintf(f
, "skip_hw ");
1256 if (flags
& TCA_CLS_FLAGS_SKIP_SW
)
1257 fprintf(f
, "skip_sw ");
1259 if (flags
& TCA_CLS_FLAGS_IN_HW
)
1260 fprintf(f
, "in_hw ");
1261 else if (flags
& TCA_CLS_FLAGS_NOT_IN_HW
)
1262 fprintf(f
, "not_in_hw ");
1265 if (tb
[TCA_U32_PCNT
]) {
1266 if (RTA_PAYLOAD(tb
[TCA_U32_PCNT
]) < sizeof(*pf
)) {
1267 fprintf(f
, "Broken perf counters\n");
1270 pf
= RTA_DATA(tb
[TCA_U32_PCNT
]);
1273 if (sel
&& show_stats
&& NULL
!= pf
)
1274 fprintf(f
, " (rule hit %llu success %llu)",
1275 (unsigned long long) pf
->rcnt
,
1276 (unsigned long long) pf
->rhit
);
1278 if (tb
[TCA_U32_MARK
]) {
1279 struct tc_u32_mark
*mark
= RTA_DATA(tb
[TCA_U32_MARK
]);
1281 if (RTA_PAYLOAD(tb
[TCA_U32_MARK
]) < sizeof(*mark
)) {
1282 fprintf(f
, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1284 fprintf(f
, "\n mark 0x%04x 0x%04x (success %d)",
1285 mark
->val
, mark
->mask
, mark
->success
);
1293 for (i
= 0; i
< sel
->nkeys
; i
++) {
1294 show_keys(f
, sel
->keys
+ i
);
1295 if (show_stats
&& NULL
!= pf
)
1296 fprintf(f
, " (success %llu ) ",
1297 (unsigned long long) pf
->kcnts
[i
]);
1301 if (sel
->flags
& (TC_U32_VAROFFSET
| TC_U32_OFFSET
)) {
1302 fprintf(f
, "\n offset ");
1303 if (sel
->flags
& TC_U32_VAROFFSET
)
1304 fprintf(f
, "%04x>>%d at %d ",
1305 ntohs(sel
->offmask
),
1306 sel
->offshift
, sel
->offoff
);
1308 fprintf(f
, "plus %d ", sel
->off
);
1310 if (sel
->flags
& TC_U32_EAT
)
1311 fprintf(f
, " eat ");
1314 fprintf(f
, "\n hash mask %08x at %d ",
1315 (unsigned int)htonl(sel
->hmask
), sel
->hoff
);
1319 if (tb
[TCA_U32_POLICE
]) {
1321 tc_print_police(f
, tb
[TCA_U32_POLICE
]);
1324 if (tb
[TCA_U32_INDEV
]) {
1325 struct rtattr
*idev
= tb
[TCA_U32_INDEV
];
1327 fprintf(f
, "\n input dev %s\n", rta_getattr_str(idev
));
1330 if (tb
[TCA_U32_ACT
])
1331 tc_print_action(f
, tb
[TCA_U32_ACT
], 0);
1336 struct filter_util u32_filter_util
= {
1338 .parse_fopt
= u32_parse_opt
,
1339 .print_fopt
= u32_print_opt
,