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");
41 #define usage() return(-1)
43 int get_u32_handle(__u32
*handle
, char *str
)
45 __u32 htid
=0, hash
=0, nodeid
=0;
46 char *tmp
= strchr(str
, ':');
49 if (memcmp("0x", str
, 2) == 0)
50 return get_u32(handle
, str
, 16);
53 htid
= strtoul(str
, &tmp
, 16);
54 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
60 hash
= strtoul(str
, &tmp
, 16);
61 if (tmp
== str
&& *str
!= ':' && *str
!= 0)
67 nodeid
= strtoul(str
, &tmp
, 16);
68 if (tmp
== str
&& *str
!= 0)
74 *handle
= (htid
<<20)|(hash
<<12)|nodeid
;
78 char * sprint_u32_handle(__u32 handle
, char *buf
)
80 int bsize
= SPRINT_BSIZE
-1;
81 __u32 htid
= TC_U32_HTID(handle
);
82 __u32 hash
= TC_U32_HASH(handle
);
83 __u32 nodeid
= TC_U32_NODE(handle
);
87 snprintf(b
, bsize
, "none");
91 int l
= snprintf(b
, bsize
, "%x:", htid
>>20);
97 int l
= snprintf(b
, bsize
, "%x", hash
);
102 int l
= snprintf(b
, bsize
, ":%x", nodeid
);
108 snprintf(b
, bsize
, "[%08x] ", handle
);
112 static int pack_key(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
115 int hwm
= sel
->nkeys
;
119 for (i
=0; i
<hwm
; i
++) {
120 if (sel
->keys
[i
].off
== off
&& sel
->keys
[i
].offmask
== offmask
) {
121 __u32 intersect
= mask
&sel
->keys
[i
].mask
;
123 if ((key
^sel
->keys
[i
].val
) & intersect
)
125 sel
->keys
[i
].val
|= key
;
126 sel
->keys
[i
].mask
|= mask
;
135 sel
->keys
[hwm
].val
= key
;
136 sel
->keys
[hwm
].mask
= mask
;
137 sel
->keys
[hwm
].off
= off
;
138 sel
->keys
[hwm
].offmask
= offmask
;
143 static int pack_key32(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
147 return pack_key(sel
, key
, mask
, off
, offmask
);
150 static int pack_key16(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
152 if (key
> 0xFFFF || mask
> 0xFFFF)
155 if ((off
& 3) == 0) {
163 return pack_key(sel
, key
, mask
, off
, offmask
);
166 static int pack_key8(struct tc_u32_sel
*sel
, __u32 key
, __u32 mask
, int off
, int offmask
)
168 if (key
> 0xFF || mask
> 0xFF)
171 if ((off
& 3) == 0) {
174 } else if ((off
& 3) == 1) {
177 } else if ((off
& 3) == 2) {
185 return pack_key(sel
, key
, mask
, off
, offmask
);
189 int parse_at(int *argc_p
, char ***argv_p
, int *off
, int *offmask
)
192 char **argv
= *argv_p
;
198 if (strlen(p
) > strlen("nexthdr+") &&
199 memcmp(p
, "nexthdr+", strlen("nexthdr+")) == 0) {
201 p
+= strlen("nexthdr+");
202 } else if (matches(*argv
, "nexthdr+") == 0) {
208 if (get_integer(off
, p
, 0))
218 static int parse_u32(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
, int offmask
)
222 char **argv
= *argv_p
;
229 if (get_u32(&key
, *argv
, 0))
233 if (get_u32(&mask
, *argv
, 16))
237 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
239 if (parse_at(&argc
, &argv
, &off
, &offmask
))
243 res
= pack_key32(sel
, key
, mask
, off
, offmask
);
249 static int parse_u16(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
, int offmask
)
253 char **argv
= *argv_p
;
260 if (get_u32(&key
, *argv
, 0))
264 if (get_u32(&mask
, *argv
, 16))
268 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
270 if (parse_at(&argc
, &argv
, &off
, &offmask
))
273 res
= pack_key16(sel
, key
, mask
, off
, offmask
);
279 static int parse_u8(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
, int offmask
)
283 char **argv
= *argv_p
;
290 if (get_u32(&key
, *argv
, 0))
294 if (get_u32(&mask
, *argv
, 16))
298 if (key
> 0xFF || mask
> 0xFF)
301 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
303 if (parse_at(&argc
, &argv
, &off
, &offmask
))
307 res
= pack_key8(sel
, key
, mask
, off
, offmask
);
313 static int parse_ip_addr(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
)
317 char **argv
= *argv_p
;
325 if (get_prefix_1(&addr
, *argv
, AF_INET
))
329 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
331 if (parse_at(&argc
, &argv
, &off
, &offmask
))
337 mask
= htonl(0xFFFFFFFF<<(32-addr
.bitlen
));
338 if (pack_key(sel
, addr
.data
[0], mask
, off
, offmask
) < 0)
347 static int parse_ip6_addr(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, int off
)
351 char **argv
= *argv_p
;
360 if (get_prefix_1(&addr
, *argv
, AF_INET6
))
364 if (argc
> 0 && strcmp(argv
[0], "at") == 0) {
366 if (parse_at(&argc
, &argv
, &off
, &offmask
))
371 for (i
=0; i
<plen
; i
+=32) {
372 // if (((i+31)&~0x1F)<=plen) {
373 if (((i
+31))<=plen
) {
374 if ((res
= pack_key(sel
, addr
.data
[i
/32], 0xFFFFFFFF, off
+4*(i
/32), offmask
)) < 0)
377 __u32 mask
= htonl(0xFFFFFFFF<<(32-(plen
-i
)));
378 if ((res
= pack_key(sel
, addr
.data
[i
/32], mask
, off
+4*(i
/32), offmask
)) < 0)
389 static int parse_ip(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
393 char **argv
= *argv_p
;
398 if (strcmp(*argv
, "src") == 0) {
400 res
= parse_ip_addr(&argc
, &argv
, sel
, 12);
403 if (strcmp(*argv
, "dst") == 0) {
405 res
= parse_ip_addr(&argc
, &argv
, sel
, 16);
408 if (strcmp(*argv
, "tos") == 0 ||
409 matches(*argv
, "dsfield") == 0) {
411 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
414 if (strcmp(*argv
, "ihl") == 0) {
416 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
419 if (strcmp(*argv
, "protocol") == 0) {
421 res
= parse_u8(&argc
, &argv
, sel
, 9, 0);
424 if (matches(*argv
, "precedence") == 0) {
426 res
= parse_u8(&argc
, &argv
, sel
, 1, 0);
429 if (strcmp(*argv
, "nofrag") == 0) {
431 res
= pack_key16(sel
, 0, 0x3FFF, 6, 0);
434 if (strcmp(*argv
, "firstfrag") == 0) {
436 res
= pack_key16(sel
, 0, 0x1FFF, 6, 0);
439 if (strcmp(*argv
, "df") == 0) {
441 res
= pack_key16(sel
, 0x4000, 0x4000, 6, 0);
444 if (strcmp(*argv
, "mf") == 0) {
446 res
= pack_key16(sel
, 0x2000, 0x2000, 6, 0);
449 if (strcmp(*argv
, "dport") == 0) {
451 res
= parse_u16(&argc
, &argv
, sel
, 22, 0);
454 if (strcmp(*argv
, "sport") == 0) {
456 res
= parse_u16(&argc
, &argv
, sel
, 20, 0);
459 if (strcmp(*argv
, "icmp_type") == 0) {
461 res
= parse_u8(&argc
, &argv
, sel
, 20, 0);
464 if (strcmp(*argv
, "icmp_code") == 0) {
466 res
= parse_u8(&argc
, &argv
, sel
, 20, 1);
477 static int parse_ip6(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
481 char **argv
= *argv_p
;
486 if (strcmp(*argv
, "src") == 0) {
488 res
= parse_ip6_addr(&argc
, &argv
, sel
, 8);
491 if (strcmp(*argv
, "dst") == 0) {
493 res
= parse_ip6_addr(&argc
, &argv
, sel
, 24);
496 if (strcmp(*argv
, "priority") == 0) {
498 res
= parse_u8(&argc
, &argv
, sel
, 4, 0);
501 if (strcmp(*argv
, "protocol") == 0) {
503 res
= parse_u8(&argc
, &argv
, sel
, 6, 0);
506 if (strcmp(*argv
, "flowlabel") == 0) {
508 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
511 if (strcmp(*argv
, "dport") == 0) {
513 res
= parse_u16(&argc
, &argv
, sel
, 42, 0);
516 if (strcmp(*argv
, "sport") == 0) {
518 res
= parse_u16(&argc
, &argv
, sel
, 40, 0);
521 if (strcmp(*argv
, "icmp_type") == 0) {
523 res
= parse_u8(&argc
, &argv
, sel
, 40, 0);
526 if (strcmp(*argv
, "icmp_code") == 0) {
528 res
= parse_u8(&argc
, &argv
, sel
, 41, 1);
539 #define parse_tcp parse_udp
540 static int parse_udp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
544 char **argv
= *argv_p
;
549 if (strcmp(*argv
, "src") == 0) {
551 res
= parse_u16(&argc
, &argv
, sel
, 0, -1);
554 if (strcmp(*argv
, "dst") == 0) {
556 res
= parse_u16(&argc
, &argv
, sel
, 2, -1);
567 static int parse_icmp(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
571 char **argv
= *argv_p
;
576 if (strcmp(*argv
, "type") == 0) {
578 res
= parse_u8(&argc
, &argv
, sel
, 0, -1);
581 if (strcmp(*argv
, "code") == 0) {
583 res
= parse_u8(&argc
, &argv
, sel
, 1, -1);
594 static int parse_mark(int *argc_p
, char ***argv_p
, struct nlmsghdr
*n
)
598 char **argv
= *argv_p
;
599 struct tc_u32_mark mark
;
604 if (get_u32(&mark
.val
, *argv
, 0)) {
605 fprintf(stderr
, "Illegal \"mark\" value\n");
610 if (get_u32(&mark
.mask
, *argv
, 0)) {
611 fprintf(stderr
, "Illegal \"mark\" mask\n");
616 if ((mark
.val
& mark
.mask
) != mark
.val
) {
617 fprintf(stderr
, "Illegal \"mark\" (impossible combination)\n");
621 addattr_l(n
, MAX_MSG
, TCA_U32_MARK
, &mark
, sizeof(mark
));
629 static int parse_selector(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
, struct nlmsghdr
*n
)
632 char **argv
= *argv_p
;
638 if (matches(*argv
, "u32") == 0) {
640 res
= parse_u32(&argc
, &argv
, sel
, 0, 0);
643 if (matches(*argv
, "u16") == 0) {
645 res
= parse_u16(&argc
, &argv
, sel
, 0, 0);
648 if (matches(*argv
, "u8") == 0) {
650 res
= parse_u8(&argc
, &argv
, sel
, 0, 0);
653 if (matches(*argv
, "ip") == 0) {
655 res
= parse_ip(&argc
, &argv
, sel
);
658 if (matches(*argv
, "ip6") == 0) {
660 res
= parse_ip6(&argc
, &argv
, sel
);
663 if (matches(*argv
, "udp") == 0) {
665 res
= parse_udp(&argc
, &argv
, sel
);
668 if (matches(*argv
, "tcp") == 0) {
670 res
= parse_tcp(&argc
, &argv
, sel
);
673 if (matches(*argv
, "icmp") == 0) {
675 res
= parse_icmp(&argc
, &argv
, sel
);
678 if (matches(*argv
, "mark") == 0) {
680 res
= parse_mark(&argc
, &argv
, n
);
692 static int parse_offset(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
695 char **argv
= *argv_p
;
698 if (matches(*argv
, "plus") == 0) {
701 if (get_integer(&off
, *argv
, 0))
704 sel
->flags
|= TC_U32_OFFSET
;
705 } else if (matches(*argv
, "at") == 0) {
708 if (get_integer(&off
, *argv
, 0))
712 fprintf(stderr
, "offset \"at\" must be even\n");
715 sel
->flags
|= TC_U32_VAROFFSET
;
716 } else if (matches(*argv
, "mask") == 0) {
719 if (get_u16(&mask
, *argv
, 16))
721 sel
->offmask
= htons(mask
);
722 sel
->flags
|= TC_U32_VAROFFSET
;
723 } else if (matches(*argv
, "shift") == 0) {
726 if (get_integer(&shift
, *argv
, 0))
728 sel
->offshift
= shift
;
729 sel
->flags
|= TC_U32_VAROFFSET
;
730 } else if (matches(*argv
, "eat") == 0) {
731 sel
->flags
|= TC_U32_EAT
;
743 static int parse_hashkey(int *argc_p
, char ***argv_p
, struct tc_u32_sel
*sel
)
746 char **argv
= *argv_p
;
749 if (matches(*argv
, "mask") == 0) {
752 if (get_u32(&mask
, *argv
, 16))
754 sel
->hmask
= htonl(mask
);
755 } else if (matches(*argv
, "at") == 0) {
758 if (get_integer(&num
, *argv
, 0))
774 static int u32_parse_opt(struct filter_util
*qu
, char *handle
, int argc
, char **argv
, struct nlmsghdr
*n
)
777 struct tc_u32_sel sel
;
778 struct tc_u32_key keys
[128];
780 struct tcmsg
*t
= NLMSG_DATA(n
);
787 memset(&sel
, 0, sizeof(sel
));
789 if (handle
&& get_u32_handle(&t
->tcm_handle
, handle
)) {
790 fprintf(stderr
, "Illegal filter ID\n");
797 tail
= NLMSG_TAIL(n
);
798 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
801 if (matches(*argv
, "match") == 0) {
803 if (parse_selector(&argc
, &argv
, &sel
.sel
, n
)) {
804 fprintf(stderr
, "Illegal \"match\"\n");
809 } else if (matches(*argv
, "offset") == 0) {
811 if (parse_offset(&argc
, &argv
, &sel
.sel
)) {
812 fprintf(stderr
, "Illegal \"offset\"\n");
816 } else if (matches(*argv
, "hashkey") == 0) {
818 if (parse_hashkey(&argc
, &argv
, &sel
.sel
)) {
819 fprintf(stderr
, "Illegal \"hashkey\"\n");
823 } else if (matches(*argv
, "classid") == 0 ||
824 strcmp(*argv
, "flowid") == 0) {
827 if (get_tc_classid(&handle
, *argv
)) {
828 fprintf(stderr
, "Illegal \"classid\"\n");
831 addattr_l(n
, MAX_MSG
, TCA_U32_CLASSID
, &handle
, 4);
832 sel
.sel
.flags
|= TC_U32_TERMINAL
;
833 } else if (matches(*argv
, "divisor") == 0) {
836 if (get_unsigned(&divisor
, *argv
, 0) ||
838 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
839 fprintf(stderr
, "Illegal \"divisor\"\n");
842 addattr_l(n
, MAX_MSG
, TCA_U32_DIVISOR
, &divisor
, 4);
843 } else if (matches(*argv
, "order") == 0) {
845 if (get_u32(&order
, *argv
, 0)) {
846 fprintf(stderr
, "Illegal \"order\"\n");
849 } else if (strcmp(*argv
, "link") == 0) {
852 if (get_u32_handle(&handle
, *argv
)) {
853 fprintf(stderr
, "Illegal \"link\"\n");
856 if (handle
&& TC_U32_NODE(handle
)) {
857 fprintf(stderr
, "\"link\" must be a hash table.\n");
860 addattr_l(n
, MAX_MSG
, TCA_U32_LINK
, &handle
, 4);
861 } else if (strcmp(*argv
, "ht") == 0) {
864 if (get_u32_handle(&handle
, *argv
)) {
865 fprintf(stderr
, "Illegal \"ht\"\n");
868 if (handle
&& TC_U32_NODE(handle
)) {
869 fprintf(stderr
, "\"ht\" must be a hash table.\n");
873 htid
= (htid
&0xFF000)|(handle
&0xFFF00000);
875 htid
= (handle
&0xFFFFF000);
876 } else if (strcmp(*argv
, "sample") == 0) {
878 unsigned divisor
= 0x100;
881 struct tc_u32_sel sel
;
882 struct tc_u32_key keys
[4];
884 memset(&sel2
, 0, sizeof(sel2
));
886 if (parse_selector(&argc
, &argv
, &sel2
.sel
, n
)) {
887 fprintf(stderr
, "Illegal \"sample\"\n");
890 if (sel2
.sel
.nkeys
!= 1) {
891 fprintf(stderr
, "\"sample\" must contain exactly ONE key.\n");
894 if (*argv
!= 0 && strcmp(*argv
, "divisor") == 0) {
896 if (get_unsigned(&divisor
, *argv
, 0) || divisor
== 0 ||
897 divisor
> 0x100 || ((divisor
- 1) & divisor
)) {
898 fprintf(stderr
, "Illegal sample \"divisor\"\n");
903 hash
= sel2
.sel
.keys
[0].val
&sel2
.sel
.keys
[0].mask
;
906 htid
= ((hash
%divisor
)<<12)|(htid
&0xFFF00000);
909 } else if (strcmp(*argv
, "indev") == 0) {
910 char ind
[IFNAMSIZ
+ 1];
911 memset(ind
, 0, sizeof (ind
));
915 fprintf(stderr
, "Illegal indev\n");
918 strncpy(ind
, *argv
, sizeof (ind
) - 1);
919 addattr_l(n
, MAX_MSG
, TCA_U32_INDEV
, ind
, strlen(ind
) + 1);
921 } else if (matches(*argv
, "action") == 0) {
923 if (parse_action(&argc
, &argv
, TCA_U32_ACT
, n
)) {
924 fprintf(stderr
, "Illegal \"action\"\n");
929 } else if (matches(*argv
, "police") == 0) {
931 if (parse_police(&argc
, &argv
, TCA_U32_POLICE
, n
)) {
932 fprintf(stderr
, "Illegal \"police\"\n");
936 } else if (strcmp(*argv
, "help") == 0) {
940 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
948 if (TC_U32_NODE(t
->tcm_handle
) && order
!= TC_U32_NODE(t
->tcm_handle
)) {
949 fprintf(stderr
, "\"order\" contradicts \"handle\"\n");
952 t
->tcm_handle
|= order
;
956 addattr_l(n
, MAX_MSG
, TCA_U32_HASH
, &htid
, 4);
958 addattr_l(n
, MAX_MSG
, TCA_U32_SEL
, &sel
, sizeof(sel
.sel
)+sel
.sel
.nkeys
*sizeof(struct tc_u32_key
));
959 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
963 static int u32_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
, __u32 handle
)
965 struct rtattr
*tb
[TCA_U32_MAX
+1];
966 struct tc_u32_sel
*sel
= NULL
;
967 struct tc_u32_pcnt
*pf
= NULL
;
972 parse_rtattr_nested(tb
, TCA_U32_MAX
, opt
);
976 fprintf(f
, "fh %s ", sprint_u32_handle(handle
, b1
));
978 if (TC_U32_NODE(handle
)) {
979 fprintf(f
, "order %d ", TC_U32_NODE(handle
));
982 if (tb
[TCA_U32_SEL
]) {
983 if (RTA_PAYLOAD(tb
[TCA_U32_SEL
]) < sizeof(*sel
))
986 sel
= RTA_DATA(tb
[TCA_U32_SEL
]);
989 if (tb
[TCA_U32_DIVISOR
]) {
990 fprintf(f
, "ht divisor %d ", *(__u32
*)RTA_DATA(tb
[TCA_U32_DIVISOR
]));
991 } else if (tb
[TCA_U32_HASH
]) {
992 __u32 htid
= *(__u32
*)RTA_DATA(tb
[TCA_U32_HASH
]);
993 fprintf(f
, "key ht %x bkt %x ", TC_U32_USERHTID(htid
), TC_U32_HASH(htid
));
997 if (tb
[TCA_U32_CLASSID
]) {
999 fprintf(f
, "%sflowid %s ",
1000 !sel
|| !(sel
->flags
&TC_U32_TERMINAL
) ? "*" : "",
1001 sprint_tc_classid(*(__u32
*)RTA_DATA(tb
[TCA_U32_CLASSID
]), b1
));
1002 } else if (sel
&& sel
->flags
&TC_U32_TERMINAL
) {
1003 fprintf(f
, "terminal flowid ??? ");
1005 if (tb
[TCA_U32_LINK
]) {
1007 fprintf(f
, "link %s ", sprint_u32_handle(*(__u32
*)RTA_DATA(tb
[TCA_U32_LINK
]), b1
));
1010 if (tb
[TCA_U32_PCNT
]) {
1011 if (RTA_PAYLOAD(tb
[TCA_U32_PCNT
]) < sizeof(*pf
)) {
1012 fprintf(f
, "Broken perf counters \n");
1015 pf
= RTA_DATA(tb
[TCA_U32_PCNT
]);
1018 if (sel
&& show_stats
&& NULL
!= pf
)
1019 fprintf(f
, " (rule hit %llu success %llu)",
1020 (unsigned long long) pf
->rcnt
,
1021 (unsigned long long) pf
->rhit
);
1023 if (tb
[TCA_U32_MARK
]) {
1024 struct tc_u32_mark
*mark
= RTA_DATA(tb
[TCA_U32_MARK
]);
1025 if (RTA_PAYLOAD(tb
[TCA_U32_MARK
]) < sizeof(*mark
)) {
1026 fprintf(f
, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1028 fprintf(f
, "\n mark 0x%04x 0x%04x (success %d)",
1029 mark
->val
, mark
->mask
, mark
->success
);
1035 struct tc_u32_key
*key
= sel
->keys
;
1037 for (i
=0; i
<sel
->nkeys
; i
++, key
++) {
1038 fprintf(f
, "\n match %08x/%08x at %s%d",
1039 (unsigned int)ntohl(key
->val
),
1040 (unsigned int)ntohl(key
->mask
),
1041 key
->offmask
? "nexthdr+" : "",
1043 if (show_stats
&& NULL
!= pf
)
1044 fprintf(f
, " (success %lld ) ",
1045 (unsigned long long) pf
->kcnts
[i
]);
1049 if (sel
->flags
&(TC_U32_VAROFFSET
|TC_U32_OFFSET
)) {
1050 fprintf(f
, "\n offset ");
1051 if (sel
->flags
&TC_U32_VAROFFSET
)
1052 fprintf(f
, "%04x>>%d at %d ", ntohs(sel
->offmask
), sel
->offshift
, sel
->offoff
);
1054 fprintf(f
, "plus %d ", sel
->off
);
1056 if (sel
->flags
&TC_U32_EAT
)
1057 fprintf(f
, " eat ");
1060 fprintf(f
, "\n hash mask %08x at %d ",
1061 (unsigned int)htonl(sel
->hmask
), sel
->hoff
);
1065 if (tb
[TCA_U32_POLICE
]) {
1067 tc_print_police(f
, tb
[TCA_U32_POLICE
]);
1069 if (tb
[TCA_U32_INDEV
]) {
1070 struct rtattr
*idev
= tb
[TCA_U32_INDEV
];
1071 fprintf(f
, "\n input dev %s\n", (char *) RTA_DATA(idev
));
1073 if (tb
[TCA_U32_ACT
]) {
1074 tc_print_action(f
, tb
[TCA_U32_ACT
]);
1080 struct filter_util u32_filter_util
= {
1082 .parse_fopt
= u32_parse_opt
,
1083 .print_fopt
= u32_print_opt
,