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>
28 static void explain(void)
30 fprintf(stderr
, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n");
31 fprintf(stderr
, " [ police POLICE_SPEC ] [ offset OFFSET_SPEC ]\n");
32 fprintf(stderr
, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
33 fprintf(stderr
, " [ sample SAMPLE ]\n");
34 fprintf(stderr
, "or u32 divisor DIVISOR\n");
35 fprintf(stderr
, "\n");
36 fprintf(stderr
, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
37 fprintf(stderr
, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
38 fprintf(stderr
, " FILTERID := X:Y:Z\n");
39 fprintf(stderr
, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
42 #define usage() return(-1)
44 int get_u32_handle(__u32
*handle
, 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 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);
98 int l
= snprintf(b
, bsize
, "%x", hash
);
103 int l
= snprintf(b
, bsize
, ":%x", nodeid
);
109 snprintf(b
, bsize
, "[%08x] ", handle
);
113 static int pack_key(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
116 int hwm
= sel
->nkeys
;
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
;
124 if ((key
^sel
->keys
[i
].val
) & intersect
)
126 sel
->keys
[i
].val
|= key
;
127 sel
->keys
[i
].mask
|= mask
;
136 sel
->keys
[hwm
].val
= key
;
137 sel
->keys
[hwm
].mask
= mask
;
138 sel
->keys
[hwm
].off
= off
;
139 sel
->keys
[hwm
].offmask
= offmask
;
144 static int pack_key32(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
148 return pack_key(sel
, key
, mask
, off
, offmask
);
151 static int pack_key16(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
153 if (key
> 0xFFFF || mask
> 0xFFFF)
156 if ((off
& 3) == 0) {
164 return pack_key(sel
, key
, mask
, off
, offmask
);
167 static int pack_key8(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
169 if (key
> 0xFF || mask
> 0xFF)
172 if ((off
& 3) == 0) {
175 } else if ((off
& 3) == 1) {
178 } else if ((off
& 3) == 2) {
186 return pack_key(sel
, key
, mask
, off
, offmask
);
190 int parse_at(int *argc_p
, char ***argv_p
, int *off
, int *offmask
)
193 char **argv
= *argv_p
;
199 if (strlen(p
) > strlen("nexthdr+") &&
200 memcmp(p
, "nexthdr+", strlen("nexthdr+")) == 0) {
202 p
+= strlen("nexthdr+");
203 } else if (matches(*argv
, "nexthdr+") == 0) {
209 if (get_integer(off
, p
, 0))
219 static int parse_u32(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
, int offmask
)
223 char **argv
= *argv_p
;
230 if (get_u32(&key
, *argv
, 0))
234 if (get_u32(&mask
, *argv
, 16))
238 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
240 if (parse_at(&argc
, &argv
, &off
, &offmask
))
244 res
= pack_key32(sel
, key
, mask
, off
, offmask
);
250 static int parse_u16(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
, int offmask
)
254 char **argv
= *argv_p
;
261 if (get_u32(&key
, *argv
, 0))
265 if (get_u32(&mask
, *argv
, 16))
269 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
271 if (parse_at(&argc
, &argv
, &off
, &offmask
))
274 res
= pack_key16(sel
, key
, mask
, off
, offmask
);
280 static int parse_u8(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
, int offmask
)
284 char **argv
= *argv_p
;
291 if (get_u32(&key
, *argv
, 0))
295 if (get_u32(&mask
, *argv
, 16))
299 if (key
> 0xFF || mask
> 0xFF)
302 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
304 if (parse_at(&argc
, &argv
, &off
, &offmask
))
308 res
= pack_key8(sel
, key
, mask
, off
, offmask
);
314 static int parse_ip_addr(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
)
318 char **argv
= *argv_p
;
326 if (get_prefix_1(&addr
, *argv
, AF_INET
))
330 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
332 if (parse_at(&argc
, &argv
, &off
, &offmask
))
338 mask
= htonl(0xFFFFFFFF<<(32-addr
.bitlen
));
339 if (pack_key(sel
, addr
.data
[0], mask
, off
, offmask
) < 0)
348 static int parse_ip6_addr(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
)
352 char **argv
= *argv_p
;
361 if (get_prefix_1(&addr
, *argv
, AF_INET6
))
365 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
367 if (parse_at(&argc
, &argv
, &off
, &offmask
))
372 for (i
=0; i
<plen
; i
+=32) {
373 // if (((i+31)&~0x1F)<=plen) {
374 if (((i
+31))<=plen
) {
375 if ((res
= pack_key(sel
, addr
.data
[i
/32], 0xFFFFFFFF, off
+4*(i
/32), offmask
)) < 0)
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)
390 static int parse_ip(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
394 char **argv
= *argv_p
;
399 if (strcmp(*argv
, "src") == 0) {
401 res
= parse_ip_addr(&argc
, &argv
, sel
, 12);
404 if (strcmp(*argv
, "dst") == 0) {
406 res
= parse_ip_addr(&argc
, &argv
, sel
, 16);
409 if (strcmp(*argv
, "tos") == 0 ||
410 matches(*argv
, "dsfield") == 0) {
412 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
415 if (strcmp(*argv
, "ihl") == 0) {
417 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
420 if (strcmp(*argv
, "protocol") == 0) {
422 res
= parse_u8(&argc
, &argv
, sel
, 9, 0);
425 if (matches(*argv
, "precedence") == 0) {
427 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
430 if (strcmp(*argv
, "nofrag") == 0) {
432 res
= pack_key16(sel
, 0, 0x3FFF, 6, 0);
435 if (strcmp(*argv
, "firstfrag") == 0) {
437 res
= pack_key16(sel
, 0, 0x1FFF, 6, 0);
440 if (strcmp(*argv
, "df") == 0) {
442 res
= pack_key16(sel
, 0x4000, 0x4000, 6, 0);
445 if (strcmp(*argv
, "mf") == 0) {
447 res
= pack_key16(sel
, 0x2000, 0x2000, 6, 0);
450 if (strcmp(*argv
, "dport") == 0) {
452 res
= parse_u16(&argc
, &argv
, sel
, 22, 0);
455 if (strcmp(*argv
, "sport") == 0) {
457 res
= parse_u16(&argc
, &argv
, sel
, 20, 0);
460 if (strcmp(*argv
, "icmp_type") == 0) {
462 res
= parse_u8(&argc
, &argv
, sel
, 20, 0);
465 if (strcmp(*argv
, "icmp_code") == 0) {
467 res
= parse_u8(&argc
, &argv
, sel
, 20, 1);
478 static int parse_ip6(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
482 char **argv
= *argv_p
;
487 if (strcmp(*argv
, "src") == 0) {
489 res
= parse_ip6_addr(&argc
, &argv
, sel
, 8);
492 if (strcmp(*argv
, "dst") == 0) {
494 res
= parse_ip6_addr(&argc
, &argv
, sel
, 24);
497 if (strcmp(*argv
, "priority") == 0) {
499 res
= parse_u8(&argc
, &argv
, sel
, 4, 0);
502 if (strcmp(*argv
, "protocol") == 0) {
504 res
= parse_u8(&argc
, &argv
, sel
, 6, 0);
507 if (strcmp(*argv
, "flowlabel") == 0) {
509 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
512 if (strcmp(*argv
, "dport") == 0) {
514 res
= parse_u16(&argc
, &argv
, sel
, 42, 0);
517 if (strcmp(*argv
, "sport") == 0) {
519 res
= parse_u16(&argc
, &argv
, sel
, 40, 0);
522 if (strcmp(*argv
, "icmp_type") == 0) {
524 res
= parse_u8(&argc
, &argv
, sel
, 40, 0);
527 if (strcmp(*argv
, "icmp_code") == 0) {
529 res
= parse_u8(&argc
, &argv
, sel
, 41, 1);
540 #define parse_tcp parse_udp
541 static int parse_udp(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_u16(&argc
, &argv
, sel
, 0, -1);
555 if (strcmp(*argv
, "dst") == 0) {
557 res
= parse_u16(&argc
, &argv
, sel
, 2, -1);
569 static int parse_icmp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
573 char **argv
= *argv_p
;
578 if (strcmp(*argv
, "type") == 0) {
580 res
= parse_u8(&argc
, &argv
, sel
, 0, -1);
583 if (strcmp(*argv
, "code") == 0) {
585 res
= parse_u8(&argc
, &argv
, sel
, 1, -1);
596 static int parse_mark(int *argc_p
, char ***argv_p
, struct nlmsghdr
*n
)
600 char **argv
= *argv_p
;
601 struct tc_u32_mark mark
;
606 if (get_u32(&mark
.val
, *argv
, 0)) {
607 fprintf(stderr
, "Illegal \"mark\" value\n");
612 if (get_u32(&mark
.mask
, *argv
, 0)) {
613 fprintf(stderr
, "Illegal \"mark\" mask\n");
618 if ((mark
.val
& mark
.mask
) != mark
.val
) {
619 fprintf(stderr
, "Illegal \"mark\" (impossible combination)\n");
623 addattr_l(n
, MAX_MSG
, TCA_U32_MARK
, &mark
, sizeof(mark
));
631 static int parse_selector(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, struct nlmsghdr
*n
)
634 char **argv
= *argv_p
;
640 if (matches(*argv
, "u32") == 0) {
642 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
645 if (matches(*argv
, "u16") == 0) {
647 res
= parse_u16(&argc
, &argv
, sel
, 0, 0);
650 if (matches(*argv
, "u8") == 0) {
652 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
655 if (matches(*argv
, "ip") == 0) {
657 res
= parse_ip(&argc
, &argv
, sel
);
660 if (matches(*argv
, "ip6") == 0) {
662 res
= parse_ip6(&argc
, &argv
, sel
);
665 if (matches(*argv
, "udp") == 0) {
667 res
= parse_udp(&argc
, &argv
, sel
);
670 if (matches(*argv
, "tcp") == 0) {
672 res
= parse_tcp(&argc
, &argv
, sel
);
675 if (matches(*argv
, "icmp") == 0) {
677 res
= parse_icmp(&argc
, &argv
, sel
);
680 if (matches(*argv
, "mark") == 0) {
682 res
= parse_mark(&argc
, &argv
, n
);
694 static int parse_offset(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
697 char **argv
= *argv_p
;
700 if (matches(*argv
, "plus") == 0) {
703 if (get_integer(&off
, *argv
, 0))
706 sel
->flags
|= TC_U32_OFFSET
;
707 } else if (matches(*argv
, "at") == 0) {
710 if (get_integer(&off
, *argv
, 0))
714 fprintf(stderr
, "offset \"at\" must be even\n");
717 sel
->flags
|= TC_U32_VAROFFSET
;
718 } else if (matches(*argv
, "mask") == 0) {
721 if (get_u16(&mask
, *argv
, 16))
723 sel
->offmask
= htons(mask
);
724 sel
->flags
|= TC_U32_VAROFFSET
;
725 } else if (matches(*argv
, "shift") == 0) {
728 if (get_integer(&shift
, *argv
, 0))
730 sel
->offshift
= shift
;
731 sel
->flags
|= TC_U32_VAROFFSET
;
732 } else if (matches(*argv
, "eat") == 0) {
733 sel
->flags
|= TC_U32_EAT
;
745 static int parse_hashkey(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
748 char **argv
= *argv_p
;
751 if (matches(*argv
, "mask") == 0) {
754 if (get_u32(&mask
, *argv
, 16))
756 sel
->hmask
= htonl(mask
);
757 } else if (matches(*argv
, "at") == 0) {
760 if (get_integer(&num
, *argv
, 0))
776 static void show_key(FILE *f
, const struct tc_u32_key
*key
)
786 int bits
= mask2bits(key
->mask
);
788 fprintf(f
, "\n %s %s/%d\n",
789 key
->off
== 12 ? "src" : "dst",
790 inet_ntop(AF_INET
, &key
->val
, abuf
, sizeof(abuf
)),
799 if (key
->mask
== ntohl(0xffff)) {
800 fprintf(f
, "\n %s %u\n",
801 key
->off
== 20 ? "sport" : "dport",
802 (unsigned short) ntohl(key
->val
));
808 fprintf(f
, "\n match %08x/%08x at %s%d",
809 (unsigned int)ntohl(key
->val
),
810 (unsigned int)ntohl(key
->mask
),
811 key
->offmask
? "nexthdr+" : "",
815 static int u32_parse_opt(struct filter_util
*qu
, char *handle
,
816 int argc
, char **argv
, struct nlmsghdr
*n
)
819 struct tc_u32_sel sel
;
820 struct tc_u32_key keys
[128];
822 struct tcmsg
*t
= NLMSG_DATA(n
);
824 int sel_ok
= 0, terminal_ok
= 0;
829 memset(&sel
, 0, sizeof(sel
));
831 if (handle
&& get_u32_handle(&t
->tcm_handle
, handle
)) {
832 fprintf(stderr
, "Illegal filter ID\n");
839 tail
= NLMSG_TAIL(n
);
840 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
843 if (matches(*argv
, "match") == 0) {
845 if (parse_selector(&argc
, &argv
, &sel
.sel
, n
)) {
846 fprintf(stderr
, "Illegal \"match\"\n");
851 } else if (matches(*argv
, "offset") == 0) {
853 if (parse_offset(&argc
, &argv
, &sel
.sel
)) {
854 fprintf(stderr
, "Illegal \"offset\"\n");
858 } else if (matches(*argv
, "hashkey") == 0) {
860 if (parse_hashkey(&argc
, &argv
, &sel
.sel
)) {
861 fprintf(stderr
, "Illegal \"hashkey\"\n");
865 } else if (matches(*argv
, "classid") == 0 ||
866 strcmp(*argv
, "flowid") == 0) {
869 if (get_tc_classid(&handle
, *argv
)) {
870 fprintf(stderr
, "Illegal \"classid\"\n");
873 addattr_l(n
, MAX_MSG
, TCA_U32_CLASSID
, &handle
, 4);
874 sel
.sel
.flags
|= TC_U32_TERMINAL
;
875 } else if (matches(*argv
, "divisor") == 0) {
878 if (get_unsigned(&divisor
, *argv
, 0) ||
880 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
881 fprintf(stderr
, "Illegal \"divisor\"\n");
884 addattr_l(n
, MAX_MSG
, TCA_U32_DIVISOR
, &divisor
, 4);
885 } else if (matches(*argv
, "order") == 0) {
887 if (get_u32(&order
, *argv
, 0)) {
888 fprintf(stderr
, "Illegal \"order\"\n");
891 } else if (strcmp(*argv
, "link") == 0) {
894 if (get_u32_handle(&handle
, *argv
)) {
895 fprintf(stderr
, "Illegal \"link\"\n");
898 if (handle
&& TC_U32_NODE(handle
)) {
899 fprintf(stderr
, "\"link\" must be a hash table.\n");
902 addattr_l(n
, MAX_MSG
, TCA_U32_LINK
, &handle
, 4);
903 } else if (strcmp(*argv
, "ht") == 0) {
906 if (get_u32_handle(&handle
, *argv
)) {
907 fprintf(stderr
, "Illegal \"ht\"\n");
910 if (handle
&& TC_U32_NODE(handle
)) {
911 fprintf(stderr
, "\"ht\" must be a hash table.\n");
915 htid
= (htid
&0xFF000)|(handle
&0xFFF00000);
917 htid
= (handle
&0xFFFFF000);
918 } else if (strcmp(*argv
, "sample") == 0) {
920 unsigned divisor
= 0x100;
923 struct tc_u32_sel sel
;
924 struct tc_u32_key keys
[4];
926 memset(&sel2
, 0, sizeof(sel2
));
928 if (parse_selector(&argc
, &argv
, &sel2
.sel
, n
)) {
929 fprintf(stderr
, "Illegal \"sample\"\n");
932 if (sel2
.sel
.nkeys
!= 1) {
933 fprintf(stderr
, "\"sample\" must contain exactly ONE key.\n");
936 if (*argv
!= 0 && strcmp(*argv
, "divisor") == 0) {
938 if (get_unsigned(&divisor
, *argv
, 0) || divisor
== 0 ||
939 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
940 fprintf(stderr
, "Illegal sample \"divisor\"\n");
945 hash
= sel2
.sel
.keys
[0].val
&sel2
.sel
.keys
[0].mask
;
948 htid
= ((hash
%divisor
)<<12)|(htid
&0xFFF00000);
951 } else if (strcmp(*argv
, "indev") == 0) {
952 char ind
[IFNAMSIZ
+ 1];
953 memset(ind
, 0, sizeof (ind
));
957 fprintf(stderr
, "Illegal indev\n");
960 strncpy(ind
, *argv
, sizeof (ind
) - 1);
961 addattr_l(n
, MAX_MSG
, TCA_U32_INDEV
, ind
, strlen(ind
) + 1);
963 } else if (matches(*argv
, "action") == 0) {
965 if (parse_action(&argc
, &argv
, TCA_U32_ACT
, n
)) {
966 fprintf(stderr
, "Illegal \"action\"\n");
972 } else if (matches(*argv
, "police") == 0) {
974 if (parse_police(&argc
, &argv
, TCA_U32_POLICE
, n
)) {
975 fprintf(stderr
, "Illegal \"police\"\n");
980 } else if (strcmp(*argv
, "help") == 0) {
984 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
991 /* We dont necessarily need class/flowids */
993 sel
.sel
.flags
|= TC_U32_TERMINAL
;
996 if (TC_U32_NODE(t
->tcm_handle
) && order
!= TC_U32_NODE(t
->tcm_handle
)) {
997 fprintf(stderr
, "\"order\" contradicts \"handle\"\n");
1000 t
->tcm_handle
|= order
;
1004 addattr_l(n
, MAX_MSG
, TCA_U32_HASH
, &htid
, 4);
1006 addattr_l(n
, MAX_MSG
, TCA_U32_SEL
, &sel
, sizeof(sel
.sel
)+sel
.sel
.nkeys
*sizeof(struct tc_u32_key
));
1007 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
1011 static int u32_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
,
1014 struct rtattr
*tb
[TCA_U32_MAX
+1];
1015 struct tc_u32_sel
*sel
= NULL
;
1016 struct tc_u32_pcnt
*pf
= NULL
;
1021 parse_rtattr_nested(tb
, TCA_U32_MAX
, opt
);
1025 fprintf(f
, "fh %s ", sprint_u32_handle(handle
, b1
));
1027 if (TC_U32_NODE(handle
)) {
1028 fprintf(f
, "order %d ", TC_U32_NODE(handle
));
1031 if (tb
[TCA_U32_SEL
]) {
1032 if (RTA_PAYLOAD(tb
[TCA_U32_SEL
]) < sizeof(*sel
))
1035 sel
= RTA_DATA(tb
[TCA_U32_SEL
]);
1038 if (tb
[TCA_U32_DIVISOR
]) {
1039 fprintf(f
, "ht divisor %d ", *(__u32
*)RTA_DATA(tb
[TCA_U32_DIVISOR
]));
1040 } else if (tb
[TCA_U32_HASH
]) {
1041 __u32 htid
= *(__u32
*)RTA_DATA(tb
[TCA_U32_HASH
]);
1042 fprintf(f
, "key ht %x bkt %x ", TC_U32_USERHTID(htid
), TC_U32_HASH(htid
));
1046 if (tb
[TCA_U32_CLASSID
]) {
1048 fprintf(f
, "%sflowid %s ",
1049 !sel
|| !(sel
->flags
&TC_U32_TERMINAL
) ? "*" : "",
1050 sprint_tc_classid(*(__u32
*)RTA_DATA(tb
[TCA_U32_CLASSID
]), b1
));
1051 } else if (sel
&& sel
->flags
&TC_U32_TERMINAL
) {
1052 fprintf(f
, "terminal flowid ??? ");
1054 if (tb
[TCA_U32_LINK
]) {
1056 fprintf(f
, "link %s ", sprint_u32_handle(*(__u32
*)RTA_DATA(tb
[TCA_U32_LINK
]), b1
));
1059 if (tb
[TCA_U32_PCNT
]) {
1060 if (RTA_PAYLOAD(tb
[TCA_U32_PCNT
]) < sizeof(*pf
)) {
1061 fprintf(f
, "Broken perf counters \n");
1064 pf
= RTA_DATA(tb
[TCA_U32_PCNT
]);
1067 if (sel
&& show_stats
&& NULL
!= pf
)
1068 fprintf(f
, " (rule hit %llu success %llu)",
1069 (unsigned long long) pf
->rcnt
,
1070 (unsigned long long) pf
->rhit
);
1072 if (tb
[TCA_U32_MARK
]) {
1073 struct tc_u32_mark
*mark
= RTA_DATA(tb
[TCA_U32_MARK
]);
1074 if (RTA_PAYLOAD(tb
[TCA_U32_MARK
]) < sizeof(*mark
)) {
1075 fprintf(f
, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1077 fprintf(f
, "\n mark 0x%04x 0x%04x (success %d)",
1078 mark
->val
, mark
->mask
, mark
->success
);
1085 for (i
=0; i
<sel
->nkeys
; i
++) {
1086 show_key(f
, sel
->keys
+ i
);
1087 if (show_stats
&& NULL
!= pf
)
1088 fprintf(f
, " (success %llu ) ",
1089 (unsigned long long) pf
->kcnts
[i
]);
1093 if (sel
->flags
&(TC_U32_VAROFFSET
|TC_U32_OFFSET
)) {
1094 fprintf(f
, "\n offset ");
1095 if (sel
->flags
&TC_U32_VAROFFSET
)
1096 fprintf(f
, "%04x>>%d at %d ", ntohs(sel
->offmask
), sel
->offshift
, sel
->offoff
);
1098 fprintf(f
, "plus %d ", sel
->off
);
1100 if (sel
->flags
&TC_U32_EAT
)
1101 fprintf(f
, " eat ");
1104 fprintf(f
, "\n hash mask %08x at %d ",
1105 (unsigned int)htonl(sel
->hmask
), sel
->hoff
);
1109 if (tb
[TCA_U32_POLICE
]) {
1111 tc_print_police(f
, tb
[TCA_U32_POLICE
]);
1113 if (tb
[TCA_U32_INDEV
]) {
1114 struct rtattr
*idev
= tb
[TCA_U32_INDEV
];
1115 fprintf(f
, "\n input dev %s\n", (char *) RTA_DATA(idev
));
1117 if (tb
[TCA_U32_ACT
]) {
1118 tc_print_action(f
, tb
[TCA_U32_ACT
]);
1124 struct filter_util u32_filter_util
= {
1126 .parse_fopt
= u32_parse_opt
,
1127 .print_fopt
= u32_print_opt
,