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 ]"
31 " [ classid CLASSID ]\n");
32 fprintf(stderr
, " [ police POLICE_SPEC ]"
33 " [ offset OFFSET_SPEC ]\n");
34 fprintf(stderr
, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
35 fprintf(stderr
, " [ sample SAMPLE ]\n");
36 fprintf(stderr
, "or u32 divisor DIVISOR\n");
37 fprintf(stderr
, "\n");
38 fprintf(stderr
, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
39 fprintf(stderr
, " SAMPLE := { ip | ip6 | udp | tcp | icmp |"
40 " u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
41 fprintf(stderr
, " FILTERID := X:Y:Z\n");
42 fprintf(stderr
, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
45 #define usage() return(-1)
47 int get_u32_handle(__u32
*handle
, 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 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);
101 int l
= snprintf(b
, bsize
, "%x", hash
);
106 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
, int offmask
)
175 if (key
> 0xFF || mask
> 0xFF)
178 if ((off
& 3) == 0) {
181 } else if ((off
& 3) == 1) {
184 } else if ((off
& 3) == 2) {
192 return pack_key(sel
, key
, mask
, off
, offmask
);
196 int parse_at(int *argc_p
, char ***argv_p
, int *off
, int *offmask
)
199 char **argv
= *argv_p
;
205 if (strlen(p
) > strlen("nexthdr+") &&
206 memcmp(p
, "nexthdr+", strlen("nexthdr+")) == 0) {
208 p
+= strlen("nexthdr+");
209 } else if (matches(*argv
, "nexthdr+") == 0) {
215 if (get_integer(off
, p
, 0))
225 static int parse_u32(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
226 int off
, int offmask
)
230 char **argv
= *argv_p
;
237 if (get_u32(&key
, *argv
, 0))
241 if (get_u32(&mask
, *argv
, 16))
245 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
247 if (parse_at(&argc
, &argv
, &off
, &offmask
))
251 res
= pack_key32(sel
, key
, mask
, off
, offmask
);
257 static int parse_u16(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
258 int off
, int offmask
)
262 char **argv
= *argv_p
;
269 if (get_u32(&key
, *argv
, 0))
273 if (get_u32(&mask
, *argv
, 16))
277 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
279 if (parse_at(&argc
, &argv
, &off
, &offmask
))
282 res
= pack_key16(sel
, key
, mask
, off
, offmask
);
288 static int parse_u8(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
289 int off
, int offmask
)
293 char **argv
= *argv_p
;
300 if (get_u32(&key
, *argv
, 0))
304 if (get_u32(&mask
, *argv
, 16))
308 if (key
> 0xFF || mask
> 0xFF)
311 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
313 if (parse_at(&argc
, &argv
, &off
, &offmask
))
317 res
= pack_key8(sel
, key
, mask
, off
, offmask
);
323 static int parse_ip_addr(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
,
328 char **argv
= *argv_p
;
336 if (get_prefix_1(&addr
, *argv
, AF_INET
))
340 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
342 if (parse_at(&argc
, &argv
, &off
, &offmask
))
348 mask
= htonl(0xFFFFFFFF<<(32-addr
.bitlen
));
349 if (pack_key(sel
, addr
.data
[0], mask
, off
, offmask
) < 0)
358 static int parse_ip6_addr(int *argc_p
, char ***argv_p
,
359 struct tc_u32_sel
*sel
, int off
)
363 char **argv
= *argv_p
;
372 if (get_prefix_1(&addr
, *argv
, AF_INET6
))
376 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
378 if (parse_at(&argc
, &argv
, &off
, &offmask
))
383 for (i
=0; i
<plen
; i
+=32) {
384 // if (((i+31)&~0x1F)<=plen) {
385 if (i
+ 31 <= plen
) {
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
)));
392 res
= pack_key(sel
, addr
.data
[i
/32],
393 mask
, off
+4*(i
/32), offmask
);
405 static int parse_ip(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
409 char **argv
= *argv_p
;
414 if (strcmp(*argv
, "src") == 0) {
416 res
= parse_ip_addr(&argc
, &argv
, sel
, 12);
419 if (strcmp(*argv
, "dst") == 0) {
421 res
= parse_ip_addr(&argc
, &argv
, sel
, 16);
424 if (strcmp(*argv
, "tos") == 0 ||
425 matches(*argv
, "dsfield") == 0) {
427 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
430 if (strcmp(*argv
, "ihl") == 0) {
432 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
435 if (strcmp(*argv
, "protocol") == 0) {
437 res
= parse_u8(&argc
, &argv
, sel
, 9, 0);
440 if (matches(*argv
, "precedence") == 0) {
442 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
445 if (strcmp(*argv
, "nofrag") == 0) {
447 res
= pack_key16(sel
, 0, 0x3FFF, 6, 0);
450 if (strcmp(*argv
, "firstfrag") == 0) {
452 res
= pack_key16(sel
, 0, 0x1FFF, 6, 0);
455 if (strcmp(*argv
, "df") == 0) {
457 res
= pack_key16(sel
, 0x4000, 0x4000, 6, 0);
460 if (strcmp(*argv
, "mf") == 0) {
462 res
= pack_key16(sel
, 0x2000, 0x2000, 6, 0);
465 if (strcmp(*argv
, "dport") == 0) {
467 res
= parse_u16(&argc
, &argv
, sel
, 22, 0);
470 if (strcmp(*argv
, "sport") == 0) {
472 res
= parse_u16(&argc
, &argv
, sel
, 20, 0);
475 if (strcmp(*argv
, "icmp_type") == 0) {
477 res
= parse_u8(&argc
, &argv
, sel
, 20, 0);
480 if (strcmp(*argv
, "icmp_code") == 0) {
482 res
= parse_u8(&argc
, &argv
, sel
, 20, 1);
493 static int parse_ip6(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
497 char **argv
= *argv_p
;
502 if (strcmp(*argv
, "src") == 0) {
504 res
= parse_ip6_addr(&argc
, &argv
, sel
, 8);
507 if (strcmp(*argv
, "dst") == 0) {
509 res
= parse_ip6_addr(&argc
, &argv
, sel
, 24);
512 if (strcmp(*argv
, "priority") == 0) {
514 res
= parse_u8(&argc
, &argv
, sel
, 4, 0);
517 if (strcmp(*argv
, "protocol") == 0) {
519 res
= parse_u8(&argc
, &argv
, sel
, 6, 0);
522 if (strcmp(*argv
, "flowlabel") == 0) {
524 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
527 if (strcmp(*argv
, "dport") == 0) {
529 res
= parse_u16(&argc
, &argv
, sel
, 42, 0);
532 if (strcmp(*argv
, "sport") == 0) {
534 res
= parse_u16(&argc
, &argv
, sel
, 40, 0);
537 if (strcmp(*argv
, "icmp_type") == 0) {
539 res
= parse_u8(&argc
, &argv
, sel
, 40, 0);
542 if (strcmp(*argv
, "icmp_code") == 0) {
544 res
= parse_u8(&argc
, &argv
, sel
, 41, 1);
555 #define parse_tcp parse_udp
556 static int parse_udp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
560 char **argv
= *argv_p
;
565 if (strcmp(*argv
, "src") == 0) {
567 res
= parse_u16(&argc
, &argv
, sel
, 0, -1);
570 if (strcmp(*argv
, "dst") == 0) {
572 res
= parse_u16(&argc
, &argv
, sel
, 2, -1);
584 static int parse_icmp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
588 char **argv
= *argv_p
;
593 if (strcmp(*argv
, "type") == 0) {
595 res
= parse_u8(&argc
, &argv
, sel
, 0, -1);
598 if (strcmp(*argv
, "code") == 0) {
600 res
= parse_u8(&argc
, &argv
, sel
, 1, -1);
611 static int parse_mark(int *argc_p
, char ***argv_p
, struct nlmsghdr
*n
)
615 char **argv
= *argv_p
;
616 struct tc_u32_mark mark
;
621 if (get_u32(&mark
.val
, *argv
, 0)) {
622 fprintf(stderr
, "Illegal \"mark\" value\n");
627 if (get_u32(&mark
.mask
, *argv
, 0)) {
628 fprintf(stderr
, "Illegal \"mark\" mask\n");
633 if ((mark
.val
& mark
.mask
) != mark
.val
) {
634 fprintf(stderr
, "Illegal \"mark\" (impossible combination)\n");
638 addattr_l(n
, MAX_MSG
, TCA_U32_MARK
, &mark
, sizeof(mark
));
646 static int parse_selector(int *argc_p
, char ***argv_p
,
647 struct tc_u32_sel
*sel
, struct nlmsghdr
*n
)
650 char **argv
= *argv_p
;
656 if (matches(*argv
, "u32") == 0) {
658 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
661 if (matches(*argv
, "u16") == 0) {
663 res
= parse_u16(&argc
, &argv
, sel
, 0, 0);
666 if (matches(*argv
, "u8") == 0) {
668 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
671 if (matches(*argv
, "ip") == 0) {
673 res
= parse_ip(&argc
, &argv
, sel
);
676 if (matches(*argv
, "ip6") == 0) {
678 res
= parse_ip6(&argc
, &argv
, sel
);
681 if (matches(*argv
, "udp") == 0) {
683 res
= parse_udp(&argc
, &argv
, sel
);
686 if (matches(*argv
, "tcp") == 0) {
688 res
= parse_tcp(&argc
, &argv
, sel
);
691 if (matches(*argv
, "icmp") == 0) {
693 res
= parse_icmp(&argc
, &argv
, sel
);
696 if (matches(*argv
, "mark") == 0) {
698 res
= parse_mark(&argc
, &argv
, n
);
710 static int parse_offset(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
713 char **argv
= *argv_p
;
716 if (matches(*argv
, "plus") == 0) {
719 if (get_integer(&off
, *argv
, 0))
722 sel
->flags
|= TC_U32_OFFSET
;
723 } else if (matches(*argv
, "at") == 0) {
726 if (get_integer(&off
, *argv
, 0))
730 fprintf(stderr
, "offset \"at\" must be even\n");
733 sel
->flags
|= TC_U32_VAROFFSET
;
734 } else if (matches(*argv
, "mask") == 0) {
737 if (get_u16(&mask
, *argv
, 16))
739 sel
->offmask
= htons(mask
);
740 sel
->flags
|= TC_U32_VAROFFSET
;
741 } else if (matches(*argv
, "shift") == 0) {
744 if (get_integer(&shift
, *argv
, 0))
746 sel
->offshift
= shift
;
747 sel
->flags
|= TC_U32_VAROFFSET
;
748 } else if (matches(*argv
, "eat") == 0) {
749 sel
->flags
|= TC_U32_EAT
;
761 static int parse_hashkey(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
764 char **argv
= *argv_p
;
767 if (matches(*argv
, "mask") == 0) {
770 if (get_u32(&mask
, *argv
, 16))
772 sel
->hmask
= htonl(mask
);
773 } else if (matches(*argv
, "at") == 0) {
776 if (get_integer(&num
, *argv
, 0))
792 static void show_key(FILE *f
, const struct tc_u32_key
*key
)
802 int bits
= mask2bits(key
->mask
);
804 fprintf(f
, "\n %s %s/%d\n",
805 key
->off
== 12 ? "src" : "dst",
806 inet_ntop(AF_INET
, &key
->val
,
816 if (key
->mask
== ntohl(0xffff)) {
817 fprintf(f
, "\n %s %u\n",
818 key
->off
== 20 ? "sport" : "dport",
819 (unsigned short) ntohl(key
->val
));
825 fprintf(f
, "\n match %08x/%08x at %s%d",
826 (unsigned int)ntohl(key
->val
),
827 (unsigned int)ntohl(key
->mask
),
828 key
->offmask
? "nexthdr+" : "",
832 static int u32_parse_opt(struct filter_util
*qu
, char *handle
,
833 int argc
, char **argv
, struct nlmsghdr
*n
)
836 struct tc_u32_sel sel
;
837 struct tc_u32_key keys
[128];
839 struct tcmsg
*t
= NLMSG_DATA(n
);
841 int sel_ok
= 0, terminal_ok
= 0;
846 memset(&sel
, 0, sizeof(sel
));
848 if (handle
&& get_u32_handle(&t
->tcm_handle
, handle
)) {
849 fprintf(stderr
, "Illegal filter ID\n");
856 tail
= NLMSG_TAIL(n
);
857 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
860 if (matches(*argv
, "match") == 0) {
862 if (parse_selector(&argc
, &argv
, &sel
.sel
, n
)) {
863 fprintf(stderr
, "Illegal \"match\"\n");
868 } else if (matches(*argv
, "offset") == 0) {
870 if (parse_offset(&argc
, &argv
, &sel
.sel
)) {
871 fprintf(stderr
, "Illegal \"offset\"\n");
875 } else if (matches(*argv
, "hashkey") == 0) {
877 if (parse_hashkey(&argc
, &argv
, &sel
.sel
)) {
878 fprintf(stderr
, "Illegal \"hashkey\"\n");
882 } else if (matches(*argv
, "classid") == 0 ||
883 strcmp(*argv
, "flowid") == 0) {
886 if (get_tc_classid(&handle
, *argv
)) {
887 fprintf(stderr
, "Illegal \"classid\"\n");
890 addattr_l(n
, MAX_MSG
, TCA_U32_CLASSID
, &handle
, 4);
891 sel
.sel
.flags
|= TC_U32_TERMINAL
;
892 } else if (matches(*argv
, "divisor") == 0) {
895 if (get_unsigned(&divisor
, *argv
, 0) ||
897 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
898 fprintf(stderr
, "Illegal \"divisor\"\n");
901 addattr_l(n
, MAX_MSG
, TCA_U32_DIVISOR
, &divisor
, 4);
902 } else if (matches(*argv
, "order") == 0) {
904 if (get_u32(&order
, *argv
, 0)) {
905 fprintf(stderr
, "Illegal \"order\"\n");
908 } else if (strcmp(*argv
, "link") == 0) {
911 if (get_u32_handle(&handle
, *argv
)) {
912 fprintf(stderr
, "Illegal \"link\"\n");
915 if (handle
&& TC_U32_NODE(handle
)) {
916 fprintf(stderr
, "\"link\" must be a hash table.\n");
919 addattr_l(n
, MAX_MSG
, TCA_U32_LINK
, &handle
, 4);
920 } else if (strcmp(*argv
, "ht") == 0) {
923 if (get_u32_handle(&handle
, *argv
)) {
924 fprintf(stderr
, "Illegal \"ht\"\n");
927 if (handle
&& TC_U32_NODE(handle
)) {
928 fprintf(stderr
, "\"ht\" must be a hash table.\n");
932 htid
= (htid
&0xFF000)|(handle
&0xFFF00000);
934 htid
= (handle
&0xFFFFF000);
935 } else if (strcmp(*argv
, "sample") == 0) {
937 unsigned divisor
= 0x100;
940 struct tc_u32_sel sel
;
941 struct tc_u32_key keys
[4];
943 memset(&sel2
, 0, sizeof(sel2
));
945 if (parse_selector(&argc
, &argv
, &sel2
.sel
, n
)) {
946 fprintf(stderr
, "Illegal \"sample\"\n");
949 if (sel2
.sel
.nkeys
!= 1) {
950 fprintf(stderr
, "\"sample\" must contain"
951 " exactly ONE key.\n");
954 if (*argv
!= 0 && strcmp(*argv
, "divisor") == 0) {
956 if (get_unsigned(&divisor
, *argv
, 0) || divisor
== 0 ||
957 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
958 fprintf(stderr
, "Illegal sample \"divisor\"\n");
963 hash
= sel2
.sel
.keys
[0].val
&sel2
.sel
.keys
[0].mask
;
966 htid
= ((hash
%divisor
)<<12)|(htid
&0xFFF00000);
969 } else if (strcmp(*argv
, "indev") == 0) {
970 char ind
[IFNAMSIZ
+ 1];
971 memset(ind
, 0, sizeof (ind
));
975 fprintf(stderr
, "Illegal indev\n");
978 strncpy(ind
, *argv
, sizeof (ind
) - 1);
979 addattr_l(n
, MAX_MSG
, TCA_U32_INDEV
, ind
, strlen(ind
) + 1);
981 } else if (matches(*argv
, "action") == 0) {
983 if (parse_action(&argc
, &argv
, TCA_U32_ACT
, n
)) {
984 fprintf(stderr
, "Illegal \"action\"\n");
990 } else if (matches(*argv
, "police") == 0) {
992 if (parse_police(&argc
, &argv
, TCA_U32_POLICE
, n
)) {
993 fprintf(stderr
, "Illegal \"police\"\n");
998 } else if (strcmp(*argv
, "help") == 0) {
1002 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
1009 /* We dont necessarily need class/flowids */
1011 sel
.sel
.flags
|= TC_U32_TERMINAL
;
1014 if (TC_U32_NODE(t
->tcm_handle
) && order
!= TC_U32_NODE(t
->tcm_handle
)) {
1015 fprintf(stderr
, "\"order\" contradicts \"handle\"\n");
1018 t
->tcm_handle
|= order
;
1022 addattr_l(n
, MAX_MSG
, TCA_U32_HASH
, &htid
, 4);
1024 addattr_l(n
, MAX_MSG
, TCA_U32_SEL
, &sel
,
1025 sizeof(sel
.sel
)+sel
.sel
.nkeys
*sizeof(struct tc_u32_key
));
1026 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
1030 static int u32_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
,
1033 struct rtattr
*tb
[TCA_U32_MAX
+1];
1034 struct tc_u32_sel
*sel
= NULL
;
1035 struct tc_u32_pcnt
*pf
= NULL
;
1040 parse_rtattr_nested(tb
, TCA_U32_MAX
, opt
);
1044 fprintf(f
, "fh %s ", sprint_u32_handle(handle
, b1
));
1046 if (TC_U32_NODE(handle
)) {
1047 fprintf(f
, "order %d ", TC_U32_NODE(handle
));
1050 if (tb
[TCA_U32_SEL
]) {
1051 if (RTA_PAYLOAD(tb
[TCA_U32_SEL
]) < sizeof(*sel
))
1054 sel
= RTA_DATA(tb
[TCA_U32_SEL
]);
1057 if (tb
[TCA_U32_DIVISOR
]) {
1058 fprintf(f
, "ht divisor %d ", *(__u32
*)RTA_DATA(tb
[TCA_U32_DIVISOR
]));
1059 } else if (tb
[TCA_U32_HASH
]) {
1060 __u32 htid
= *(__u32
*)RTA_DATA(tb
[TCA_U32_HASH
]);
1061 fprintf(f
, "key ht %x bkt %x ", TC_U32_USERHTID(htid
),
1066 if (tb
[TCA_U32_CLASSID
]) {
1068 fprintf(f
, "%sflowid %s ",
1069 !sel
|| !(sel
->flags
&TC_U32_TERMINAL
) ? "*" : "",
1070 sprint_tc_classid(*(__u32
*)RTA_DATA(tb
[TCA_U32_CLASSID
]), b1
));
1071 } else if (sel
&& sel
->flags
&TC_U32_TERMINAL
) {
1072 fprintf(f
, "terminal flowid ??? ");
1074 if (tb
[TCA_U32_LINK
]) {
1076 fprintf(f
, "link %s ",
1077 sprint_u32_handle(*(__u32
*)RTA_DATA(tb
[TCA_U32_LINK
]), b1
));
1080 if (tb
[TCA_U32_PCNT
]) {
1081 if (RTA_PAYLOAD(tb
[TCA_U32_PCNT
]) < sizeof(*pf
)) {
1082 fprintf(f
, "Broken perf counters \n");
1085 pf
= RTA_DATA(tb
[TCA_U32_PCNT
]);
1088 if (sel
&& show_stats
&& NULL
!= pf
)
1089 fprintf(f
, " (rule hit %llu success %llu)",
1090 (unsigned long long) pf
->rcnt
,
1091 (unsigned long long) pf
->rhit
);
1093 if (tb
[TCA_U32_MARK
]) {
1094 struct tc_u32_mark
*mark
= RTA_DATA(tb
[TCA_U32_MARK
]);
1095 if (RTA_PAYLOAD(tb
[TCA_U32_MARK
]) < sizeof(*mark
)) {
1096 fprintf(f
, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1098 fprintf(f
, "\n mark 0x%04x 0x%04x (success %d)",
1099 mark
->val
, mark
->mask
, mark
->success
);
1106 for (i
=0; i
<sel
->nkeys
; i
++) {
1107 show_key(f
, sel
->keys
+ i
);
1108 if (show_stats
&& NULL
!= pf
)
1109 fprintf(f
, " (success %llu ) ",
1110 (unsigned long long) pf
->kcnts
[i
]);
1114 if (sel
->flags
&(TC_U32_VAROFFSET
|TC_U32_OFFSET
)) {
1115 fprintf(f
, "\n offset ");
1116 if (sel
->flags
&TC_U32_VAROFFSET
)
1117 fprintf(f
, "%04x>>%d at %d ",
1118 ntohs(sel
->offmask
),
1119 sel
->offshift
, sel
->offoff
);
1121 fprintf(f
, "plus %d ", sel
->off
);
1123 if (sel
->flags
&TC_U32_EAT
)
1124 fprintf(f
, " eat ");
1127 fprintf(f
, "\n hash mask %08x at %d ",
1128 (unsigned int)htonl(sel
->hmask
), sel
->hoff
);
1132 if (tb
[TCA_U32_POLICE
]) {
1134 tc_print_police(f
, tb
[TCA_U32_POLICE
]);
1136 if (tb
[TCA_U32_INDEV
]) {
1137 struct rtattr
*idev
= tb
[TCA_U32_INDEV
];
1138 fprintf(f
, "\n input dev %s\n", (char *) RTA_DATA(idev
));
1140 if (tb
[TCA_U32_ACT
]) {
1141 tc_print_action(f
, tb
[TCA_U32_ACT
]);
1147 struct filter_util u32_filter_util
= {
1149 .parse_fopt
= u32_parse_opt
,
1150 .print_fopt
= u32_print_opt
,