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]
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
24 #include <linux/if_ether.h>
29 extern int show_pretty
;
31 static void explain(void)
34 "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"
35 " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"
36 " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"
37 " [ sample SAMPLE ] [skip-hw | skip-sw]\n"
38 "or u32 divisor DIVISOR\n"
40 "Where: SELECTOR := SAMPLE SAMPLE ...\n"
41 " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n"
42 " SAMPLE_ARGS [ divisor DIVISOR ]\n"
43 " FILTERID := X:Y:Z\n"
44 "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
47 static int get_u32_handle(__u32
*handle
, const char *str
)
49 __u32 htid
= 0, hash
= 0, nodeid
= 0;
50 char *tmp
= strchr(str
, ':');
53 if (memcmp("0x", str
, 2) == 0)
54 return get_u32(handle
, str
, 16);
57 htid
= strtoul(str
, &tmp
, 16);
58 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
64 hash
= strtoul(str
, &tmp
, 16);
65 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
71 nodeid
= strtoul(str
, &tmp
, 16);
72 if (tmp
== str
&& *str
!= 0)
78 *handle
= (htid
<<20)|(hash
<<12)|nodeid
;
82 static char *sprint_u32_handle(__u32 handle
, char *buf
)
84 int bsize
= SPRINT_BSIZE
-1;
85 __u32 htid
= TC_U32_HTID(handle
);
86 __u32 hash
= TC_U32_HASH(handle
);
87 __u32 nodeid
= TC_U32_NODE(handle
);
91 snprintf(b
, bsize
, "none");
95 int l
= snprintf(b
, bsize
, "%x:", htid
>>20);
102 int l
= snprintf(b
, bsize
, "%x", hash
);
108 int l
= snprintf(b
, bsize
, ":%x", nodeid
);
115 snprintf(b
, bsize
, "[%08x] ", handle
);
119 static int pack_key(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
120 int off
, int offmask
)
123 int hwm
= sel
->nkeys
;
127 for (i
= 0; i
< hwm
; i
++) {
128 if (sel
->keys
[i
].off
== off
&& sel
->keys
[i
].offmask
== offmask
) {
129 __u32 intersect
= mask
& sel
->keys
[i
].mask
;
131 if ((key
^ sel
->keys
[i
].val
) & intersect
)
133 sel
->keys
[i
].val
|= key
;
134 sel
->keys
[i
].mask
|= mask
;
143 sel
->keys
[hwm
].val
= key
;
144 sel
->keys
[hwm
].mask
= mask
;
145 sel
->keys
[hwm
].off
= off
;
146 sel
->keys
[hwm
].offmask
= offmask
;
151 static int pack_key32(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
152 int off
, int offmask
)
156 return pack_key(sel
, key
, mask
, off
, offmask
);
159 static int pack_key16(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
160 int off
, int offmask
)
162 if (key
> 0xFFFF || mask
> 0xFFFF)
165 if ((off
& 3) == 0) {
173 return pack_key(sel
, key
, mask
, off
, offmask
);
176 static int pack_key8(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
,
179 if (key
> 0xFF || mask
> 0xFF)
182 if ((off
& 3) == 0) {
185 } else if ((off
& 3) == 1) {
188 } else if ((off
& 3) == 2) {
196 return pack_key(sel
, key
, mask
, off
, offmask
);
200 static int parse_at(int *argc_p
, char ***argv_p
, int *off
, int *offmask
)
203 char **argv
= *argv_p
;
209 if (strlen(p
) > strlen("nexthdr+") &&
210 memcmp(p
, "nexthdr+", strlen("nexthdr+")) == 0) {
212 p
+= strlen("nexthdr+");
213 } else if (matches(*argv
, "nexthdr+") == 0) {
219 if (get_integer(off
, p
, 0))
229 static int parse_u32(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
230 int off
, int offmask
)
234 char **argv
= *argv_p
;
241 if (get_u32(&key
, *argv
, 0))
245 if (get_u32(&mask
, *argv
, 16))
249 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
251 if (parse_at(&argc
, &argv
, &off
, &offmask
))
255 res
= pack_key32(sel
, key
, mask
, off
, offmask
);
261 static int parse_u16(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
262 int off
, int offmask
)
266 char **argv
= *argv_p
;
273 if (get_u32(&key
, *argv
, 0))
277 if (get_u32(&mask
, *argv
, 16))
281 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
283 if (parse_at(&argc
, &argv
, &off
, &offmask
))
286 res
= pack_key16(sel
, key
, mask
, off
, offmask
);
292 static int parse_u8(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
293 int off
, int offmask
)
297 char **argv
= *argv_p
;
304 if (get_u32(&key
, *argv
, 0))
308 if (get_u32(&mask
, *argv
, 16))
312 if (key
> 0xFF || mask
> 0xFF)
315 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
317 if (parse_at(&argc
, &argv
, &off
, &offmask
))
321 res
= pack_key8(sel
, key
, mask
, off
, offmask
);
327 static int parse_ip_addr(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
332 char **argv
= *argv_p
;
340 if (get_prefix_1(&addr
, *argv
, AF_INET
))
344 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
346 if (parse_at(&argc
, &argv
, &off
, &offmask
))
352 mask
= htonl(0xFFFFFFFF << (32 - addr
.bitlen
));
353 if (pack_key(sel
, addr
.data
[0], mask
, off
, offmask
) < 0)
362 static int parse_ip6_addr(int *argc_p
, char ***argv_p
,
363 struct tc_u32_sel
*sel
, int off
)
367 char **argv
= *argv_p
;
376 if (get_prefix_1(&addr
, *argv
, AF_INET6
))
380 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
382 if (parse_at(&argc
, &argv
, &off
, &offmask
))
387 for (i
= 0; i
< plen
; i
+= 32) {
388 /* if (((i + 31) & ~0x1F) <= plen) { */
389 if (i
+ 31 <= plen
) {
390 res
= pack_key(sel
, addr
.data
[i
/ 32],
391 0xFFFFFFFF, off
+ 4 * (i
/ 32), offmask
);
394 } else if (i
< plen
) {
395 __u32 mask
= htonl(0xFFFFFFFF << (32 - (plen
- i
)));
397 res
= pack_key(sel
, addr
.data
[i
/ 32],
398 mask
, off
+ 4 * (i
/ 32), offmask
);
410 static int parse_ip6_class(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
414 char **argv
= *argv_p
;
423 if (get_u32(&key
, *argv
, 0))
427 if (get_u32(&mask
, *argv
, 16))
431 if (key
> 0xFF || mask
> 0xFF)
439 res
= pack_key(sel
, key
, mask
, off
, offmask
);
448 static int parse_ether_addr(int *argc_p
, char ***argv_p
,
449 struct tc_u32_sel
*sel
, int off
)
453 char **argv
= *argv_p
;
461 if (sscanf(*argv
, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
462 addr
+ 0, addr
+ 1, addr
+ 2,
463 addr
+ 3, addr
+ 4, addr
+ 5) != 6) {
464 fprintf(stderr
, "parse_ether_addr: improperly formed address '%s'\n",
470 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
472 if (parse_at(&argc
, &argv
, &off
, &offmask
))
476 for (i
= 0; i
< 6; i
++) {
477 res
= pack_key8(sel
, addr
[i
], 0xFF, off
+ i
, offmask
);
487 static int parse_ip(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
491 char **argv
= *argv_p
;
496 if (strcmp(*argv
, "src") == 0) {
498 res
= parse_ip_addr(&argc
, &argv
, sel
, 12);
499 } else if (strcmp(*argv
, "dst") == 0) {
501 res
= parse_ip_addr(&argc
, &argv
, sel
, 16);
502 } else if (strcmp(*argv
, "tos") == 0 ||
503 matches(*argv
, "dsfield") == 0 ||
504 matches(*argv
, "precedence") == 0) {
506 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
507 } else if (strcmp(*argv
, "ihl") == 0) {
509 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
510 } else if (strcmp(*argv
, "protocol") == 0) {
512 res
= parse_u8(&argc
, &argv
, sel
, 9, 0);
513 } else if (strcmp(*argv
, "nofrag") == 0) {
515 res
= pack_key16(sel
, 0, 0x3FFF, 6, 0);
516 } else if (strcmp(*argv
, "firstfrag") == 0) {
518 res
= pack_key16(sel
, 0x2000, 0x3FFF, 6, 0);
519 } else if (strcmp(*argv
, "df") == 0) {
521 res
= pack_key16(sel
, 0x4000, 0x4000, 6, 0);
522 } else if (strcmp(*argv
, "mf") == 0) {
524 res
= pack_key16(sel
, 0x2000, 0x2000, 6, 0);
525 } else if (strcmp(*argv
, "dport") == 0) {
527 res
= parse_u16(&argc
, &argv
, sel
, 22, 0);
528 } else if (strcmp(*argv
, "sport") == 0) {
530 res
= parse_u16(&argc
, &argv
, sel
, 20, 0);
531 } else if (strcmp(*argv
, "icmp_type") == 0) {
533 res
= parse_u8(&argc
, &argv
, sel
, 20, 0);
534 } else if (strcmp(*argv
, "icmp_code") == 0) {
536 res
= parse_u8(&argc
, &argv
, sel
, 21, 0);
545 static int parse_ip6(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
549 char **argv
= *argv_p
;
554 if (strcmp(*argv
, "src") == 0) {
556 res
= parse_ip6_addr(&argc
, &argv
, sel
, 8);
557 } else if (strcmp(*argv
, "dst") == 0) {
559 res
= parse_ip6_addr(&argc
, &argv
, sel
, 24);
560 } else if (strcmp(*argv
, "priority") == 0) {
562 res
= parse_ip6_class(&argc
, &argv
, sel
);
563 } else if (strcmp(*argv
, "protocol") == 0) {
565 res
= parse_u8(&argc
, &argv
, sel
, 6, 0);
566 } else if (strcmp(*argv
, "flowlabel") == 0) {
568 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
569 } else if (strcmp(*argv
, "dport") == 0) {
571 res
= parse_u16(&argc
, &argv
, sel
, 42, 0);
572 } else if (strcmp(*argv
, "sport") == 0) {
574 res
= parse_u16(&argc
, &argv
, sel
, 40, 0);
575 } else if (strcmp(*argv
, "icmp_type") == 0) {
577 res
= parse_u8(&argc
, &argv
, sel
, 40, 0);
578 } else if (strcmp(*argv
, "icmp_code") == 0) {
580 res
= parse_u8(&argc
, &argv
, sel
, 41, 1);
589 static int parse_ether(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
593 char **argv
= *argv_p
;
598 if (strcmp(*argv
, "src") == 0) {
600 res
= parse_ether_addr(&argc
, &argv
, sel
, -8);
601 } else if (strcmp(*argv
, "dst") == 0) {
603 res
= parse_ether_addr(&argc
, &argv
, sel
, -14);
605 fprintf(stderr
, "Unknown match: ether %s\n", *argv
);
614 #define parse_tcp parse_udp
615 static int parse_udp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
619 char **argv
= *argv_p
;
624 if (strcmp(*argv
, "src") == 0) {
626 res
= parse_u16(&argc
, &argv
, sel
, 0, -1);
627 } else if (strcmp(*argv
, "dst") == 0) {
629 res
= parse_u16(&argc
, &argv
, sel
, 2, -1);
639 static int parse_icmp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
643 char **argv
= *argv_p
;
648 if (strcmp(*argv
, "type") == 0) {
650 res
= parse_u8(&argc
, &argv
, sel
, 0, -1);
651 } else if (strcmp(*argv
, "code") == 0) {
653 res
= parse_u8(&argc
, &argv
, sel
, 1, -1);
662 static int parse_mark(int *argc_p
, char ***argv_p
, struct nlmsghdr
*n
)
666 char **argv
= *argv_p
;
667 struct tc_u32_mark mark
;
672 if (get_u32(&mark
.val
, *argv
, 0)) {
673 fprintf(stderr
, "Illegal \"mark\" value\n");
678 if (get_u32(&mark
.mask
, *argv
, 0)) {
679 fprintf(stderr
, "Illegal \"mark\" mask\n");
684 if ((mark
.val
& mark
.mask
) != mark
.val
) {
685 fprintf(stderr
, "Illegal \"mark\" (impossible combination)\n");
689 addattr_l(n
, MAX_MSG
, TCA_U32_MARK
, &mark
, sizeof(mark
));
697 static int parse_selector(int *argc_p
, char ***argv_p
,
698 struct tc_u32_sel
*sel
, struct nlmsghdr
*n
)
701 char **argv
= *argv_p
;
707 if (matches(*argv
, "u32") == 0) {
709 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
710 } else if (matches(*argv
, "u16") == 0) {
712 res
= parse_u16(&argc
, &argv
, sel
, 0, 0);
713 } else if (matches(*argv
, "u8") == 0) {
715 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
716 } else if (matches(*argv
, "ip") == 0) {
718 res
= parse_ip(&argc
, &argv
, sel
);
719 } else if (matches(*argv
, "ip6") == 0) {
721 res
= parse_ip6(&argc
, &argv
, sel
);
722 } else if (matches(*argv
, "udp") == 0) {
724 res
= parse_udp(&argc
, &argv
, sel
);
725 } else if (matches(*argv
, "tcp") == 0) {
727 res
= parse_tcp(&argc
, &argv
, sel
);
728 } else if (matches(*argv
, "icmp") == 0) {
730 res
= parse_icmp(&argc
, &argv
, sel
);
731 } else if (matches(*argv
, "mark") == 0) {
733 res
= parse_mark(&argc
, &argv
, n
);
734 } else if (matches(*argv
, "ether") == 0) {
736 res
= parse_ether(&argc
, &argv
, sel
);
745 static int parse_offset(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
748 char **argv
= *argv_p
;
751 if (matches(*argv
, "plus") == 0) {
755 if (get_integer(&off
, *argv
, 0))
758 sel
->flags
|= TC_U32_OFFSET
;
759 } else if (matches(*argv
, "at") == 0) {
763 if (get_integer(&off
, *argv
, 0))
767 fprintf(stderr
, "offset \"at\" must be even\n");
770 sel
->flags
|= TC_U32_VAROFFSET
;
771 } else if (matches(*argv
, "mask") == 0) {
773 if (get_be16(&sel
->offmask
, *argv
, 16))
775 sel
->flags
|= TC_U32_VAROFFSET
;
776 } else if (matches(*argv
, "shift") == 0) {
780 if (get_integer(&shift
, *argv
, 0))
782 sel
->offshift
= shift
;
783 sel
->flags
|= TC_U32_VAROFFSET
;
784 } else if (matches(*argv
, "eat") == 0) {
785 sel
->flags
|= TC_U32_EAT
;
797 static int parse_hashkey(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
800 char **argv
= *argv_p
;
803 if (matches(*argv
, "mask") == 0) {
805 if (get_be32(&sel
->hmask
, *argv
, 16))
807 } else if (matches(*argv
, "at") == 0) {
811 if (get_integer(&num
, *argv
, 0))
827 static void print_ipv4(FILE *f
, const struct tc_u32_key
*key
)
833 switch (ntohl(key
->mask
)) {
835 fprintf(f
, "\n match IP ihl %u",
836 ntohl(key
->val
) >> 24);
839 fprintf(f
, "\n match IP dsfield %#x",
840 ntohl(key
->val
) >> 16);
845 if (ntohl(key
->mask
) == 0x00ff0000) {
846 fprintf(f
, "\n match IP protocol %d",
847 ntohl(key
->val
) >> 16);
853 int bits
= mask2bits(key
->mask
);
856 fprintf(f
, "\n %s %s/%d",
857 key
->off
== 12 ? "match IP src" : "match IP dst",
858 inet_ntop(AF_INET
, &key
->val
,
867 switch (ntohl(key
->mask
)) {
869 fprintf(f
, "\n match dport %u",
870 ntohl(key
->val
) & 0xffff);
873 fprintf(f
, "\n match sport %u",
874 ntohl(key
->val
) >> 16);
877 fprintf(f
, "\n match dport %u, match sport %u",
878 ntohl(key
->val
) & 0xffff,
879 ntohl(key
->val
) >> 16);
883 /* XXX: Default print_raw */
887 static void print_ipv6(FILE *f
, const struct tc_u32_key
*key
)
893 switch (ntohl(key
->mask
)) {
895 fprintf(f
, "\n match IP ihl %u",
896 ntohl(key
->val
) >> 24);
899 fprintf(f
, "\n match IP dsfield %#x",
900 ntohl(key
->val
) >> 16);
905 if (ntohl(key
->mask
) == 0x00ff0000) {
906 fprintf(f
, "\n match IP protocol %d",
907 ntohl(key
->val
) >> 16);
913 int bits
= mask2bits(key
->mask
);
916 fprintf(f
, "\n %s %s/%d",
917 key
->off
== 12 ? "match IP src" : "match IP dst",
918 inet_ntop(AF_INET
, &key
->val
,
927 switch (ntohl(key
->mask
)) {
929 fprintf(f
, "\n match sport %u",
930 ntohl(key
->val
) & 0xffff);
933 fprintf(f
, "\n match dport %u",
934 ntohl(key
->val
) >> 16);
937 fprintf(f
, "\n match sport %u, match dport %u",
938 ntohl(key
->val
) & 0xffff,
939 ntohl(key
->val
) >> 16);
943 /* XXX: Default print_raw */
947 static void print_raw(FILE *f
, const struct tc_u32_key
*key
)
949 fprintf(f
, "\n match %08x/%08x at %s%d",
950 (unsigned int)ntohl(key
->val
),
951 (unsigned int)ntohl(key
->mask
),
952 key
->offmask
? "nexthdr+" : "",
956 static const struct {
959 void (*pprinter
)(FILE *f
, const struct tc_u32_key
*key
);
960 } u32_pprinters
[] = {
962 {ETH_P_IP
, 0, print_ipv4
},
963 {ETH_P_IPV6
, 0, print_ipv6
},
966 static void show_keys(FILE *f
, const struct tc_u32_key
*key
)
973 for (i
= 0; i
< ARRAY_SIZE(u32_pprinters
); i
++) {
974 if (u32_pprinters
[i
].proto
== ntohs(f_proto
)) {
976 u32_pprinters
[i
].pprinter(f
, key
);
985 static int u32_parse_opt(struct filter_util
*qu
, char *handle
,
986 int argc
, char **argv
, struct nlmsghdr
*n
)
989 struct tc_u32_sel sel
;
990 struct tc_u32_key keys
[128];
992 struct tcmsg
*t
= NLMSG_DATA(n
);
994 int sel_ok
= 0, terminal_ok
= 0;
1000 if (handle
&& get_u32_handle(&t
->tcm_handle
, handle
)) {
1001 fprintf(stderr
, "Illegal filter ID\n");
1008 tail
= NLMSG_TAIL(n
);
1009 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
1012 if (matches(*argv
, "match") == 0) {
1014 if (parse_selector(&argc
, &argv
, &sel
.sel
, n
)) {
1015 fprintf(stderr
, "Illegal \"match\"\n");
1020 } else if (matches(*argv
, "offset") == 0) {
1022 if (parse_offset(&argc
, &argv
, &sel
.sel
)) {
1023 fprintf(stderr
, "Illegal \"offset\"\n");
1027 } else if (matches(*argv
, "hashkey") == 0) {
1029 if (parse_hashkey(&argc
, &argv
, &sel
.sel
)) {
1030 fprintf(stderr
, "Illegal \"hashkey\"\n");
1034 } else if (matches(*argv
, "classid") == 0 ||
1035 strcmp(*argv
, "flowid") == 0) {
1036 unsigned int flowid
;
1039 if (get_tc_classid(&flowid
, *argv
)) {
1040 fprintf(stderr
, "Illegal \"classid\"\n");
1043 addattr_l(n
, MAX_MSG
, TCA_U32_CLASSID
, &flowid
, 4);
1044 sel
.sel
.flags
|= TC_U32_TERMINAL
;
1045 } else if (matches(*argv
, "divisor") == 0) {
1046 unsigned int divisor
;
1049 if (get_unsigned(&divisor
, *argv
, 0) ||
1051 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
1052 fprintf(stderr
, "Illegal \"divisor\"\n");
1055 addattr_l(n
, MAX_MSG
, TCA_U32_DIVISOR
, &divisor
, 4);
1056 } else if (matches(*argv
, "order") == 0) {
1058 if (get_u32(&order
, *argv
, 0)) {
1059 fprintf(stderr
, "Illegal \"order\"\n");
1062 } else if (strcmp(*argv
, "link") == 0) {
1063 unsigned int linkid
;
1066 if (get_u32_handle(&linkid
, *argv
)) {
1067 fprintf(stderr
, "Illegal \"link\"\n");
1070 if (linkid
&& TC_U32_NODE(linkid
)) {
1071 fprintf(stderr
, "\"link\" must be a hash table.\n");
1074 addattr_l(n
, MAX_MSG
, TCA_U32_LINK
, &linkid
, 4);
1075 } else if (strcmp(*argv
, "ht") == 0) {
1079 if (get_u32_handle(&ht
, *argv
)) {
1080 fprintf(stderr
, "Illegal \"ht\"\n");
1083 if (handle
&& TC_U32_NODE(ht
)) {
1084 fprintf(stderr
, "\"ht\" must be a hash table.\n");
1088 htid
= (htid
& 0xFF000) | (ht
& 0xFFF00000);
1090 htid
= (ht
& 0xFFFFF000);
1091 } else if (strcmp(*argv
, "sample") == 0) {
1093 unsigned int divisor
= 0x100;
1095 struct tc_u32_sel sel
;
1096 struct tc_u32_key keys
[4];
1100 if (parse_selector(&argc
, &argv
, &sel2
.sel
, n
)) {
1101 fprintf(stderr
, "Illegal \"sample\"\n");
1104 if (sel2
.sel
.nkeys
!= 1) {
1105 fprintf(stderr
, "\"sample\" must contain exactly ONE key.\n");
1108 if (*argv
!= 0 && strcmp(*argv
, "divisor") == 0) {
1110 if (get_unsigned(&divisor
, *argv
, 0) ||
1111 divisor
== 0 || divisor
> 0x100 ||
1112 ((divisor
- 1) & divisor
)) {
1113 fprintf(stderr
, "Illegal sample \"divisor\"\n");
1118 hash
= sel2
.sel
.keys
[0].val
& sel2
.sel
.keys
[0].mask
;
1121 htid
= ((hash
% divisor
) << 12) | (htid
& 0xFFF00000);
1124 } else if (strcmp(*argv
, "indev") == 0) {
1125 char ind
[IFNAMSIZ
+ 1] = {};
1130 fprintf(stderr
, "Illegal indev\n");
1133 strncpy(ind
, *argv
, sizeof(ind
) - 1);
1134 addattr_l(n
, MAX_MSG
, TCA_U32_INDEV
, ind
,
1137 } else if (matches(*argv
, "action") == 0) {
1139 if (parse_action(&argc
, &argv
, TCA_U32_ACT
, n
)) {
1140 fprintf(stderr
, "Illegal \"action\"\n");
1146 } else if (matches(*argv
, "police") == 0) {
1148 if (parse_police(&argc
, &argv
, TCA_U32_POLICE
, n
)) {
1149 fprintf(stderr
, "Illegal \"police\"\n");
1154 } else if (strcmp(*argv
, "skip_hw") == 0) {
1156 flags
|= TCA_CLS_FLAGS_SKIP_HW
;
1158 } else if (strcmp(*argv
, "skip_sw") == 0) {
1160 flags
|= TCA_CLS_FLAGS_SKIP_SW
;
1162 } else if (strcmp(*argv
, "help") == 0) {
1166 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
1173 /* We dont necessarily need class/flowids */
1175 sel
.sel
.flags
|= TC_U32_TERMINAL
;
1178 if (TC_U32_NODE(t
->tcm_handle
) &&
1179 order
!= TC_U32_NODE(t
->tcm_handle
)) {
1180 fprintf(stderr
, "\"order\" contradicts \"handle\"\n");
1183 t
->tcm_handle
|= order
;
1187 addattr_l(n
, MAX_MSG
, TCA_U32_HASH
, &htid
, 4);
1189 addattr_l(n
, MAX_MSG
, TCA_U32_SEL
, &sel
,
1191 sel
.sel
.nkeys
* sizeof(struct tc_u32_key
));
1193 if (!(flags
^ (TCA_CLS_FLAGS_SKIP_HW
|
1194 TCA_CLS_FLAGS_SKIP_SW
))) {
1196 "skip_hw and skip_sw are mutually exclusive\n");
1199 addattr_l(n
, MAX_MSG
, TCA_U32_FLAGS
, &flags
, 4);
1202 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
1206 static int u32_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
,
1209 struct rtattr
*tb
[TCA_U32_MAX
+ 1];
1210 struct tc_u32_sel
*sel
= NULL
;
1211 struct tc_u32_pcnt
*pf
= NULL
;
1216 parse_rtattr_nested(tb
, TCA_U32_MAX
, opt
);
1220 fprintf(f
, "fh %s ", sprint_u32_handle(handle
, b1
));
1223 if (TC_U32_NODE(handle
))
1224 fprintf(f
, "order %d ", TC_U32_NODE(handle
));
1226 if (tb
[TCA_U32_SEL
]) {
1227 if (RTA_PAYLOAD(tb
[TCA_U32_SEL
]) < sizeof(*sel
))
1230 sel
= RTA_DATA(tb
[TCA_U32_SEL
]);
1233 if (tb
[TCA_U32_DIVISOR
]) {
1234 fprintf(f
, "ht divisor %d ",
1235 rta_getattr_u32(tb
[TCA_U32_DIVISOR
]));
1236 } else if (tb
[TCA_U32_HASH
]) {
1237 __u32 htid
= rta_getattr_u32(tb
[TCA_U32_HASH
]);
1239 fprintf(f
, "key ht %x bkt %x ", TC_U32_USERHTID(htid
),
1244 if (tb
[TCA_U32_CLASSID
]) {
1246 fprintf(f
, "%sflowid %s ",
1247 !sel
|| !(sel
->flags
& TC_U32_TERMINAL
) ? "*" : "",
1248 sprint_tc_classid(rta_getattr_u32(tb
[TCA_U32_CLASSID
]),
1250 } else if (sel
&& sel
->flags
& TC_U32_TERMINAL
) {
1251 fprintf(f
, "terminal flowid ??? ");
1253 if (tb
[TCA_U32_LINK
]) {
1255 fprintf(f
, "link %s ",
1256 sprint_u32_handle(rta_getattr_u32(tb
[TCA_U32_LINK
]),
1260 if (tb
[TCA_U32_FLAGS
]) {
1261 __u32 flags
= rta_getattr_u32(tb
[TCA_U32_FLAGS
]);
1263 if (flags
& TCA_CLS_FLAGS_SKIP_HW
)
1264 fprintf(f
, "skip_hw ");
1265 if (flags
& TCA_CLS_FLAGS_SKIP_SW
)
1266 fprintf(f
, "skip_sw ");
1269 if (tb
[TCA_U32_PCNT
]) {
1270 if (RTA_PAYLOAD(tb
[TCA_U32_PCNT
]) < sizeof(*pf
)) {
1271 fprintf(f
, "Broken perf counters\n");
1274 pf
= RTA_DATA(tb
[TCA_U32_PCNT
]);
1277 if (sel
&& show_stats
&& NULL
!= pf
)
1278 fprintf(f
, " (rule hit %llu success %llu)",
1279 (unsigned long long) pf
->rcnt
,
1280 (unsigned long long) pf
->rhit
);
1282 if (tb
[TCA_U32_MARK
]) {
1283 struct tc_u32_mark
*mark
= RTA_DATA(tb
[TCA_U32_MARK
]);
1285 if (RTA_PAYLOAD(tb
[TCA_U32_MARK
]) < sizeof(*mark
)) {
1286 fprintf(f
, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1288 fprintf(f
, "\n mark 0x%04x 0x%04x (success %d)",
1289 mark
->val
, mark
->mask
, mark
->success
);
1297 for (i
= 0; i
< sel
->nkeys
; i
++) {
1298 show_keys(f
, sel
->keys
+ i
);
1299 if (show_stats
&& NULL
!= pf
)
1300 fprintf(f
, " (success %llu ) ",
1301 (unsigned long long) pf
->kcnts
[i
]);
1305 if (sel
->flags
& (TC_U32_VAROFFSET
| TC_U32_OFFSET
)) {
1306 fprintf(f
, "\n offset ");
1307 if (sel
->flags
& TC_U32_VAROFFSET
)
1308 fprintf(f
, "%04x>>%d at %d ",
1309 ntohs(sel
->offmask
),
1310 sel
->offshift
, sel
->offoff
);
1312 fprintf(f
, "plus %d ", sel
->off
);
1314 if (sel
->flags
& TC_U32_EAT
)
1315 fprintf(f
, " eat ");
1318 fprintf(f
, "\n hash mask %08x at %d ",
1319 (unsigned int)htonl(sel
->hmask
), sel
->hoff
);
1323 if (tb
[TCA_U32_POLICE
]) {
1325 tc_print_police(f
, tb
[TCA_U32_POLICE
]);
1328 if (tb
[TCA_U32_INDEV
]) {
1329 struct rtattr
*idev
= tb
[TCA_U32_INDEV
];
1331 fprintf(f
, "\n input dev %s\n", rta_getattr_str(idev
));
1334 if (tb
[TCA_U32_ACT
])
1335 tc_print_action(f
, tb
[TCA_U32_ACT
]);
1340 struct filter_util u32_filter_util
= {
1342 .parse_fopt
= u32_parse_opt
,
1343 .print_fopt
= u32_print_opt
,