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)
33 fprintf(stderr
, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ]"
34 " [ classid CLASSID ]\n");
35 fprintf(stderr
, " [ action ACTION_SPEC ]"
36 " [ offset OFFSET_SPEC ]\n");
37 fprintf(stderr
, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
38 fprintf(stderr
, " [ sample SAMPLE ]\n");
39 fprintf(stderr
, "or u32 divisor DIVISOR\n");
40 fprintf(stderr
, "\n");
41 fprintf(stderr
, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
42 fprintf(stderr
, " SAMPLE := { ip | ip6 | udp | tcp | icmp |"
43 " u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
44 fprintf(stderr
, " FILTERID := X:Y:Z\n");
45 fprintf(stderr
, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
48 static int get_u32_handle(__u32
*handle
, const char *str
)
50 __u32 htid
=0, hash
=0, nodeid
=0;
51 char *tmp
= strchr(str
, ':');
54 if (memcmp("0x", str
, 2) == 0)
55 return get_u32(handle
, str
, 16);
58 htid
= strtoul(str
, &tmp
, 16);
59 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
65 hash
= strtoul(str
, &tmp
, 16);
66 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
72 nodeid
= strtoul(str
, &tmp
, 16);
73 if (tmp
== str
&& *str
!= 0)
79 *handle
= (htid
<<20)|(hash
<<12)|nodeid
;
83 static char * sprint_u32_handle(__u32 handle
, char *buf
)
85 int bsize
= SPRINT_BSIZE
-1;
86 __u32 htid
= TC_U32_HTID(handle
);
87 __u32 hash
= TC_U32_HASH(handle
);
88 __u32 nodeid
= TC_U32_NODE(handle
);
92 snprintf(b
, bsize
, "none");
96 int l
= snprintf(b
, bsize
, "%x:", htid
>>20);
102 int l
= snprintf(b
, bsize
, "%x", hash
);
107 int l
= snprintf(b
, bsize
, ":%x", nodeid
);
113 snprintf(b
, bsize
, "[%08x] ", handle
);
117 static int pack_key(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
118 int off
, int offmask
)
121 int hwm
= sel
->nkeys
;
125 for (i
=0; i
<hwm
; i
++) {
126 if (sel
->keys
[i
].off
== off
&& sel
->keys
[i
].offmask
== offmask
) {
127 __u32 intersect
= mask
& sel
->keys
[i
].mask
;
129 if ((key
^ sel
->keys
[i
].val
) & intersect
)
131 sel
->keys
[i
].val
|= key
;
132 sel
->keys
[i
].mask
|= mask
;
141 sel
->keys
[hwm
].val
= key
;
142 sel
->keys
[hwm
].mask
= mask
;
143 sel
->keys
[hwm
].off
= off
;
144 sel
->keys
[hwm
].offmask
= offmask
;
149 static int pack_key32(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
150 int off
, int offmask
)
154 return pack_key(sel
, key
, mask
, off
, offmask
);
157 static int pack_key16(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
,
158 int off
, int offmask
)
160 if (key
> 0xFFFF || mask
> 0xFFFF)
163 if ((off
& 3) == 0) {
171 return pack_key(sel
, key
, mask
, off
, offmask
);
174 static int pack_key8(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
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) {
385 // if (((i + 31) & ~0x1F) <= plen) {
386 if (i
+ 31 <= plen
) {
387 res
= pack_key(sel
, addr
.data
[i
/ 32],
388 0xFFFFFFFF, off
+ 4 * (i
/ 32), offmask
);
391 } else if (i
< plen
) {
392 __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) {
750 if (get_integer(&off
, *argv
, 0))
753 sel
->flags
|= TC_U32_OFFSET
;
754 } else if (matches(*argv
, "at") == 0) {
757 if (get_integer(&off
, *argv
, 0))
761 fprintf(stderr
, "offset \"at\" must be even\n");
764 sel
->flags
|= TC_U32_VAROFFSET
;
765 } else if (matches(*argv
, "mask") == 0) {
768 if (get_u16(&mask
, *argv
, 16))
770 sel
->offmask
= htons(mask
);
771 sel
->flags
|= TC_U32_VAROFFSET
;
772 } else if (matches(*argv
, "shift") == 0) {
775 if (get_integer(&shift
, *argv
, 0))
777 sel
->offshift
= shift
;
778 sel
->flags
|= TC_U32_VAROFFSET
;
779 } else if (matches(*argv
, "eat") == 0) {
780 sel
->flags
|= TC_U32_EAT
;
792 static int parse_hashkey(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
795 char **argv
= *argv_p
;
798 if (matches(*argv
, "mask") == 0) {
801 if (get_u32(&mask
, *argv
, 16))
803 sel
->hmask
= htonl(mask
);
804 } 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", ntohl(key
->val
) >> 24);
834 fprintf(f
, "\n match IP dsfield %#x", ntohl(key
->val
) >> 16);
839 if (ntohl(key
->mask
) == 0x00ff0000) {
840 fprintf(f
, "\n match IP protocol %d", ntohl(key
->val
) >> 16);
846 int bits
= mask2bits(key
->mask
);
848 fprintf(f
, "\n %s %s/%d",
849 key
->off
== 12 ? "match IP src" : "match IP dst",
850 inet_ntop(AF_INET
, &key
->val
,
859 switch (ntohl(key
->mask
)) {
861 fprintf(f
, "\n match dport %u",
862 ntohl(key
->val
) & 0xffff);
865 fprintf(f
, "\n match sport %u",
866 ntohl(key
->val
) >> 16);
869 fprintf(f
, "\n match dport %u, match sport %u",
870 ntohl(key
->val
) & 0xffff,
871 ntohl(key
->val
) >> 16);
875 /* XXX: Default print_raw */
879 static void print_ipv6(FILE *f
, const struct tc_u32_key
*key
)
885 switch (ntohl(key
->mask
)) {
887 fprintf(f
, "\n match IP ihl %u", ntohl(key
->val
) >> 24);
890 fprintf(f
, "\n match IP dsfield %#x", ntohl(key
->val
) >> 16);
895 if (ntohl(key
->mask
) == 0x00ff0000) {
896 fprintf(f
, "\n match IP protocol %d", ntohl(key
->val
) >> 16);
902 int bits
= mask2bits(key
->mask
);
904 fprintf(f
, "\n %s %s/%d",
905 key
->off
== 12 ? "match IP src" : "match IP dst",
906 inet_ntop(AF_INET
, &key
->val
,
915 switch (ntohl(key
->mask
)) {
917 fprintf(f
, "\n match sport %u",
918 ntohl(key
->val
) & 0xffff);
921 fprintf(f
, "\n match dport %u",
922 ntohl(key
->val
) >> 16);
925 fprintf(f
, "\n match sport %u, match dport %u",
926 ntohl(key
->val
) & 0xffff,
927 ntohl(key
->val
) >> 16);
931 /* XXX: Default print_raw */
935 static void print_raw(FILE *f
, const struct tc_u32_key
*key
)
937 fprintf(f
, "\n match %08x/%08x at %s%d",
938 (unsigned int)ntohl(key
->val
),
939 (unsigned int)ntohl(key
->mask
),
940 key
->offmask
? "nexthdr+" : "",
944 static const struct {
947 void (*pprinter
)(FILE *f
, const struct tc_u32_key
*key
);
948 } u32_pprinters
[] = {
950 {ETH_P_IP
, 0, print_ipv4
},
951 {ETH_P_IPV6
, 0, print_ipv6
},
954 static void show_keys(FILE *f
, const struct tc_u32_key
*key
)
961 for (i
= 0; i
< sizeof(u32_pprinters
) / sizeof(u32_pprinters
[0]); i
++) {
962 if (u32_pprinters
[i
].proto
== ntohs(f_proto
)) {
964 u32_pprinters
[i
].pprinter(f
, key
);
973 static int u32_parse_opt(struct filter_util
*qu
, char *handle
,
974 int argc
, char **argv
, struct nlmsghdr
*n
)
977 struct tc_u32_sel sel
;
978 struct tc_u32_key keys
[128];
980 struct tcmsg
*t
= NLMSG_DATA(n
);
982 int sel_ok
= 0, terminal_ok
= 0;
987 memset(&sel
, 0, sizeof(sel
));
989 if (handle
&& get_u32_handle(&t
->tcm_handle
, handle
)) {
990 fprintf(stderr
, "Illegal filter ID\n");
997 tail
= NLMSG_TAIL(n
);
998 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
1001 if (matches(*argv
, "match") == 0) {
1003 if (parse_selector(&argc
, &argv
, &sel
.sel
, n
)) {
1004 fprintf(stderr
, "Illegal \"match\"\n");
1009 } else if (matches(*argv
, "offset") == 0) {
1011 if (parse_offset(&argc
, &argv
, &sel
.sel
)) {
1012 fprintf(stderr
, "Illegal \"offset\"\n");
1016 } else if (matches(*argv
, "hashkey") == 0) {
1018 if (parse_hashkey(&argc
, &argv
, &sel
.sel
)) {
1019 fprintf(stderr
, "Illegal \"hashkey\"\n");
1023 } else if (matches(*argv
, "classid") == 0 ||
1024 strcmp(*argv
, "flowid") == 0) {
1027 if (get_tc_classid(&handle
, *argv
)) {
1028 fprintf(stderr
, "Illegal \"classid\"\n");
1031 addattr_l(n
, MAX_MSG
, TCA_U32_CLASSID
, &handle
, 4);
1032 sel
.sel
.flags
|= TC_U32_TERMINAL
;
1033 } else if (matches(*argv
, "divisor") == 0) {
1036 if (get_unsigned(&divisor
, *argv
, 0) ||
1038 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
1039 fprintf(stderr
, "Illegal \"divisor\"\n");
1042 addattr_l(n
, MAX_MSG
, TCA_U32_DIVISOR
, &divisor
, 4);
1043 } else if (matches(*argv
, "order") == 0) {
1045 if (get_u32(&order
, *argv
, 0)) {
1046 fprintf(stderr
, "Illegal \"order\"\n");
1049 } else if (strcmp(*argv
, "link") == 0) {
1052 if (get_u32_handle(&handle
, *argv
)) {
1053 fprintf(stderr
, "Illegal \"link\"\n");
1056 if (handle
&& TC_U32_NODE(handle
)) {
1057 fprintf(stderr
, "\"link\" must be a hash table.\n");
1060 addattr_l(n
, MAX_MSG
, TCA_U32_LINK
, &handle
, 4);
1061 } else if (strcmp(*argv
, "ht") == 0) {
1064 if (get_u32_handle(&handle
, *argv
)) {
1065 fprintf(stderr
, "Illegal \"ht\"\n");
1068 if (handle
&& TC_U32_NODE(handle
)) {
1069 fprintf(stderr
, "\"ht\" must be a hash table.\n");
1073 htid
= (htid
& 0xFF000) | (handle
& 0xFFF00000);
1075 htid
= (handle
& 0xFFFFF000);
1076 } else if (strcmp(*argv
, "sample") == 0) {
1078 unsigned divisor
= 0x100;
1081 struct tc_u32_sel sel
;
1082 struct tc_u32_key keys
[4];
1084 memset(&sel2
, 0, sizeof(sel2
));
1086 if (parse_selector(&argc
, &argv
, &sel2
.sel
, n
)) {
1087 fprintf(stderr
, "Illegal \"sample\"\n");
1090 if (sel2
.sel
.nkeys
!= 1) {
1091 fprintf(stderr
, "\"sample\" must contain"
1092 " exactly ONE key.\n");
1095 if (*argv
!= 0 && strcmp(*argv
, "divisor") == 0) {
1097 if (get_unsigned(&divisor
, *argv
, 0) || divisor
== 0 ||
1098 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
1099 fprintf(stderr
, "Illegal sample \"divisor\"\n");
1104 hash
= sel2
.sel
.keys
[0].val
& sel2
.sel
.keys
[0].mask
;
1107 htid
= ((hash
% divisor
) << 12) | (htid
& 0xFFF00000);
1110 } else if (strcmp(*argv
, "indev") == 0) {
1111 char ind
[IFNAMSIZ
+ 1];
1112 memset(ind
, 0, sizeof (ind
));
1116 fprintf(stderr
, "Illegal indev\n");
1119 strncpy(ind
, *argv
, sizeof (ind
) - 1);
1120 addattr_l(n
, MAX_MSG
, TCA_U32_INDEV
, ind
, strlen(ind
) + 1);
1122 } else if (matches(*argv
, "action") == 0) {
1124 if (parse_action(&argc
, &argv
, TCA_U32_ACT
, n
)) {
1125 fprintf(stderr
, "Illegal \"action\"\n");
1131 } else if (matches(*argv
, "police") == 0) {
1133 if (parse_police(&argc
, &argv
, TCA_U32_POLICE
, n
)) {
1134 fprintf(stderr
, "Illegal \"police\"\n");
1139 } else if (strcmp(*argv
, "help") == 0) {
1143 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
1150 /* We dont necessarily need class/flowids */
1152 sel
.sel
.flags
|= TC_U32_TERMINAL
;
1155 if (TC_U32_NODE(t
->tcm_handle
) && order
!= TC_U32_NODE(t
->tcm_handle
)) {
1156 fprintf(stderr
, "\"order\" contradicts \"handle\"\n");
1159 t
->tcm_handle
|= order
;
1163 addattr_l(n
, MAX_MSG
, TCA_U32_HASH
, &htid
, 4);
1165 addattr_l(n
, MAX_MSG
, TCA_U32_SEL
, &sel
,
1166 sizeof(sel
.sel
) + sel
.sel
.nkeys
* sizeof(struct tc_u32_key
));
1167 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
1171 static int u32_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
,
1174 struct rtattr
*tb
[TCA_U32_MAX
+ 1];
1175 struct tc_u32_sel
*sel
= NULL
;
1176 struct tc_u32_pcnt
*pf
= NULL
;
1181 parse_rtattr_nested(tb
, TCA_U32_MAX
, opt
);
1185 fprintf(f
, "fh %s ", sprint_u32_handle(handle
, b1
));
1187 if (TC_U32_NODE(handle
)) {
1188 fprintf(f
, "order %d ", TC_U32_NODE(handle
));
1191 if (tb
[TCA_U32_SEL
]) {
1192 if (RTA_PAYLOAD(tb
[TCA_U32_SEL
]) < sizeof(*sel
))
1195 sel
= RTA_DATA(tb
[TCA_U32_SEL
]);
1198 if (tb
[TCA_U32_DIVISOR
]) {
1199 fprintf(f
, "ht divisor %d ", rta_getattr_u32(tb
[TCA_U32_DIVISOR
]));
1200 } else if (tb
[TCA_U32_HASH
]) {
1201 __u32 htid
= rta_getattr_u32(tb
[TCA_U32_HASH
]);
1202 fprintf(f
, "key ht %x bkt %x ", TC_U32_USERHTID(htid
),
1207 if (tb
[TCA_U32_CLASSID
]) {
1209 fprintf(f
, "%sflowid %s ",
1210 !sel
|| !(sel
->flags
& TC_U32_TERMINAL
) ? "*" : "",
1211 sprint_tc_classid(rta_getattr_u32(tb
[TCA_U32_CLASSID
]), b1
));
1212 } else if (sel
&& sel
->flags
& TC_U32_TERMINAL
) {
1213 fprintf(f
, "terminal flowid ??? ");
1215 if (tb
[TCA_U32_LINK
]) {
1217 fprintf(f
, "link %s ",
1218 sprint_u32_handle(rta_getattr_u32(tb
[TCA_U32_LINK
]), b1
));
1221 if (tb
[TCA_U32_PCNT
]) {
1222 if (RTA_PAYLOAD(tb
[TCA_U32_PCNT
]) < sizeof(*pf
)) {
1223 fprintf(f
, "Broken perf counters \n");
1226 pf
= RTA_DATA(tb
[TCA_U32_PCNT
]);
1229 if (sel
&& show_stats
&& NULL
!= pf
)
1230 fprintf(f
, " (rule hit %llu success %llu)",
1231 (unsigned long long) pf
->rcnt
,
1232 (unsigned long long) pf
->rhit
);
1234 if (tb
[TCA_U32_MARK
]) {
1235 struct tc_u32_mark
*mark
= RTA_DATA(tb
[TCA_U32_MARK
]);
1236 if (RTA_PAYLOAD(tb
[TCA_U32_MARK
]) < sizeof(*mark
)) {
1237 fprintf(f
, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1239 fprintf(f
, "\n mark 0x%04x 0x%04x (success %d)",
1240 mark
->val
, mark
->mask
, mark
->success
);
1247 for (i
=0; i
<sel
->nkeys
; i
++) {
1248 show_keys(f
, sel
->keys
+ i
);
1249 if (show_stats
&& NULL
!= pf
)
1250 fprintf(f
, " (success %llu ) ",
1251 (unsigned long long) pf
->kcnts
[i
]);
1255 if (sel
->flags
& (TC_U32_VAROFFSET
| TC_U32_OFFSET
)) {
1256 fprintf(f
, "\n offset ");
1257 if (sel
->flags
& TC_U32_VAROFFSET
)
1258 fprintf(f
, "%04x>>%d at %d ",
1259 ntohs(sel
->offmask
),
1260 sel
->offshift
, sel
->offoff
);
1262 fprintf(f
, "plus %d ", sel
->off
);
1264 if (sel
->flags
& TC_U32_EAT
)
1265 fprintf(f
, " eat ");
1268 fprintf(f
, "\n hash mask %08x at %d ",
1269 (unsigned int)htonl(sel
->hmask
), sel
->hoff
);
1273 if (tb
[TCA_U32_POLICE
]) {
1275 tc_print_police(f
, tb
[TCA_U32_POLICE
]);
1277 if (tb
[TCA_U32_INDEV
]) {
1278 struct rtattr
*idev
= tb
[TCA_U32_INDEV
];
1279 fprintf(f
, "\n input dev %s\n", rta_getattr_str(idev
));
1281 if (tb
[TCA_U32_ACT
]) {
1282 tc_print_action(f
, tb
[TCA_U32_ACT
]);
1288 struct filter_util u32_filter_util
= {
1290 .parse_fopt
= u32_parse_opt
,
1291 .print_fopt
= u32_print_opt
,