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]
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
23 #include <linux/if_ether.h>
28 static void explain(void)
31 "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"
32 " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"
33 " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"
34 " [ sample SAMPLE ] [skip_hw | skip_sw]\n"
35 "or u32 divisor DIVISOR\n"
37 "Where: SELECTOR := SAMPLE SAMPLE ...\n"
38 " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n"
39 " SAMPLE_ARGS [ divisor DIVISOR ]\n"
40 " FILTERID := X:Y:Z\n"
41 "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
44 static int get_u32_handle(__u32 *handle, const 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 static 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);
99 int l = snprintf(b, bsize, "%x", hash);
105 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,
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) {
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)));
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) {
751 if (get_integer(&off, *argv, 0))
754 sel->flags |= TC_U32_OFFSET;
755 } else if (matches(*argv, "at") == 0) {
759 if (get_integer(&off, *argv, 0))
763 fprintf(stderr, "offset \"at\" must be even\n");
766 sel->flags |= TC_U32_VAROFFSET;
767 } else if (matches(*argv, "mask") == 0) {
769 if (get_be16(&sel->offmask, *argv, 16))
771 sel->flags |= TC_U32_VAROFFSET;
772 } else if (matches(*argv, "shift") == 0) {
776 if (get_integer(&shift, *argv, 0))
778 sel->offshift = shift;
779 sel->flags |= TC_U32_VAROFFSET;
780 } else if (matches(*argv, "eat") == 0) {
781 sel->flags |= TC_U32_EAT;
793 static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
796 char **argv = *argv_p;
799 if (matches(*argv, "mask") == 0) {
801 if (get_be32(&sel->hmask, *argv, 16))
803 } 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",
832 ntohl(key->val) >> 24);
835 fprintf(f, "\n match IP dsfield %#x",
836 ntohl(key->val) >> 16);
841 if (ntohl(key->mask) == 0x00ff0000) {
842 fprintf(f, "\n match IP protocol %d",
843 ntohl(key->val) >> 16);
849 int bits = mask2bits(key->mask);
852 fprintf(f, "\n %s %s/%d",
853 key->off == 12 ? "match IP src" : "match IP dst",
854 inet_ntop(AF_INET, &key->val,
863 switch (ntohl(key->mask)) {
865 fprintf(f, "\n match dport %u",
866 ntohl(key->val) & 0xffff);
869 fprintf(f, "\n match sport %u",
870 ntohl(key->val) >> 16);
873 fprintf(f, "\n match dport %u, match sport %u",
874 ntohl(key->val) & 0xffff,
875 ntohl(key->val) >> 16);
879 /* XXX: Default print_raw */
883 static void print_ipv6(FILE *f, const struct tc_u32_key *key)
889 switch (ntohl(key->mask)) {
891 fprintf(f, "\n match IP ihl %u",
892 ntohl(key->val) >> 24);
895 fprintf(f, "\n match IP dsfield %#x",
896 ntohl(key->val) >> 16);
901 if (ntohl(key->mask) == 0x00ff0000) {
902 fprintf(f, "\n match IP protocol %d",
903 ntohl(key->val) >> 16);
909 int bits = mask2bits(key->mask);
912 fprintf(f, "\n %s %s/%d",
913 key->off == 12 ? "match IP src" : "match IP dst",
914 inet_ntop(AF_INET, &key->val,
923 switch (ntohl(key->mask)) {
925 fprintf(f, "\n match sport %u",
926 ntohl(key->val) & 0xffff);
929 fprintf(f, "\n match dport %u",
930 ntohl(key->val) >> 16);
933 fprintf(f, "\n match sport %u, match dport %u",
934 ntohl(key->val) & 0xffff,
935 ntohl(key->val) >> 16);
939 /* XXX: Default print_raw */
943 static void print_raw(FILE *f, const struct tc_u32_key *key)
945 fprintf(f, "\n match %08x/%08x at %s%d",
946 (unsigned int)ntohl(key->val),
947 (unsigned int)ntohl(key->mask),
948 key->offmask ? "nexthdr+" : "",
952 static const struct {
955 void (*pprinter)(FILE *f, const struct tc_u32_key *key);
956 } u32_pprinters[] = {
958 {ETH_P_IP, 0, print_ipv4},
959 {ETH_P_IPV6, 0, print_ipv6},
962 static void show_keys(FILE *f, const struct tc_u32_key *key)
969 for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
970 if (u32_pprinters[i].proto == ntohs(f_proto)) {
972 u32_pprinters[i].pprinter(f, key);
981 static int u32_parse_opt(struct filter_util *qu, char *handle,
982 int argc, char **argv, struct nlmsghdr *n)
985 struct tc_u32_sel sel;
986 struct tc_u32_key keys[128];
988 struct tcmsg *t = NLMSG_DATA(n);
990 int sel_ok = 0, terminal_ok = 0;
996 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
997 fprintf(stderr, "Illegal filter ID\n");
1004 tail = addattr_nest(n, MAX_MSG, TCA_OPTIONS);
1007 if (matches(*argv, "match") == 0) {
1009 if (parse_selector(&argc, &argv, &sel.sel, n)) {
1010 fprintf(stderr, "Illegal \"match\"\n");
1015 } else if (matches(*argv, "offset") == 0) {
1017 if (parse_offset(&argc, &argv, &sel.sel)) {
1018 fprintf(stderr, "Illegal \"offset\"\n");
1022 } else if (matches(*argv, "hashkey") == 0) {
1024 if (parse_hashkey(&argc, &argv, &sel.sel)) {
1025 fprintf(stderr, "Illegal \"hashkey\"\n");
1029 } else if (matches(*argv, "classid") == 0 ||
1030 strcmp(*argv, "flowid") == 0) {
1031 unsigned int flowid;
1034 if (get_tc_classid(&flowid, *argv)) {
1035 fprintf(stderr, "Illegal \"classid\"\n");
1038 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4);
1039 sel.sel.flags |= TC_U32_TERMINAL;
1040 } else if (matches(*argv, "divisor") == 0) {
1041 unsigned int divisor;
1044 if (get_unsigned(&divisor, *argv, 0) ||
1046 divisor > 0x100 || ((divisor - 1) & divisor)) {
1047 fprintf(stderr, "Illegal \"divisor\"\n");
1050 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
1051 } else if (matches(*argv, "order") == 0) {
1053 if (get_u32(&order, *argv, 0)) {
1054 fprintf(stderr, "Illegal \"order\"\n");
1057 } else if (strcmp(*argv, "link") == 0) {
1058 unsigned int linkid;
1061 if (get_u32_handle(&linkid, *argv)) {
1062 fprintf(stderr, "Illegal \"link\"\n");
1065 if (linkid && TC_U32_NODE(linkid)) {
1066 fprintf(stderr, "\"link\" must be a hash table.\n");
1069 addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4);
1070 } else if (strcmp(*argv, "ht") == 0) {
1074 if (get_u32_handle(&ht, *argv)) {
1075 fprintf(stderr, "Illegal \"ht\"\n");
1078 if (handle && TC_U32_NODE(ht)) {
1079 fprintf(stderr, "\"ht\" must be a hash table.\n");
1083 htid = (htid & 0xFF000) | (ht & 0xFFF00000);
1085 htid = (ht & 0xFFFFF000);
1086 } else if (strcmp(*argv, "sample") == 0) {
1088 unsigned int divisor = 0x100;
1090 struct tc_u32_sel sel;
1091 struct tc_u32_key keys[4];
1095 if (parse_selector(&argc, &argv, &sel2.sel, n)) {
1096 fprintf(stderr, "Illegal \"sample\"\n");
1099 if (sel2.sel.nkeys != 1) {
1100 fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
1103 if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1105 if (get_unsigned(&divisor, *argv, 0) ||
1106 divisor == 0 || divisor > 0x100 ||
1107 ((divisor - 1) & divisor)) {
1108 fprintf(stderr, "Illegal sample \"divisor\"\n");
1113 hash = sel2.sel.keys[0].val & sel2.sel.keys[0].mask;
1116 htid = ((hash % divisor) << 12) | (htid & 0xFFF00000);
1119 } else if (strcmp(*argv, "indev") == 0) {
1120 char ind[IFNAMSIZ + 1] = {};
1125 fprintf(stderr, "Illegal indev\n");
1128 strncpy(ind, *argv, sizeof(ind) - 1);
1129 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind,
1132 } else if (matches(*argv, "action") == 0) {
1134 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1135 fprintf(stderr, "Illegal \"action\"\n");
1141 } else if (matches(*argv, "police") == 0) {
1143 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1144 fprintf(stderr, "Illegal \"police\"\n");
1149 } else if (strcmp(*argv, "skip_hw") == 0) {
1150 flags |= TCA_CLS_FLAGS_SKIP_HW;
1151 } else if (strcmp(*argv, "skip_sw") == 0) {
1152 flags |= TCA_CLS_FLAGS_SKIP_SW;
1153 } else if (strcmp(*argv, "help") == 0) {
1157 fprintf(stderr, "What is \"%s\"?\n", *argv);
1164 /* We don't necessarily need class/flowids */
1166 sel.sel.flags |= TC_U32_TERMINAL;
1169 if (TC_U32_NODE(t->tcm_handle) &&
1170 order != TC_U32_NODE(t->tcm_handle)) {
1171 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1174 t->tcm_handle |= order;
1178 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
1180 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
1182 sel.sel.nkeys * sizeof(struct tc_u32_key));
1184 if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW |
1185 TCA_CLS_FLAGS_SKIP_SW))) {
1187 "skip_hw and skip_sw are mutually exclusive\n");
1190 addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
1193 addattr_nest_end(n, tail);
1197 static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1200 struct rtattr *tb[TCA_U32_MAX + 1];
1201 struct tc_u32_sel *sel = NULL;
1202 struct tc_u32_pcnt *pf = NULL;
1207 parse_rtattr_nested(tb, TCA_U32_MAX, opt);
1211 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1214 if (TC_U32_NODE(handle))
1215 fprintf(f, "order %d ", TC_U32_NODE(handle));
1217 if (tb[TCA_U32_SEL]) {
1218 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
1221 sel = RTA_DATA(tb[TCA_U32_SEL]);
1224 if (tb[TCA_U32_DIVISOR]) {
1225 fprintf(f, "ht divisor %d ",
1226 rta_getattr_u32(tb[TCA_U32_DIVISOR]));
1227 } else if (tb[TCA_U32_HASH]) {
1228 __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]);
1230 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1235 if (tb[TCA_U32_CLASSID]) {
1237 fprintf(f, "%sflowid %s ",
1238 !sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "",
1239 sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]),
1241 } else if (sel && sel->flags & TC_U32_TERMINAL) {
1242 fprintf(f, "terminal flowid ??? ");
1244 if (tb[TCA_U32_LINK]) {
1246 fprintf(f, "link %s ",
1247 sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]),
1251 if (tb[TCA_U32_FLAGS]) {
1252 __u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]);
1254 if (flags & TCA_CLS_FLAGS_SKIP_HW)
1255 fprintf(f, "skip_hw ");
1256 if (flags & TCA_CLS_FLAGS_SKIP_SW)
1257 fprintf(f, "skip_sw ");
1259 if (flags & TCA_CLS_FLAGS_IN_HW)
1260 fprintf(f, "in_hw ");
1261 else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
1262 fprintf(f, "not_in_hw ");
1265 if (tb[TCA_U32_PCNT]) {
1266 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) {
1267 fprintf(f, "Broken perf counters\n");
1270 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1273 if (sel && show_stats && NULL != pf)
1274 fprintf(f, " (rule hit %llu success %llu)",
1275 (unsigned long long) pf->rcnt,
1276 (unsigned long long) pf->rhit);
1278 if (tb[TCA_U32_MARK]) {
1279 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1281 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1282 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1284 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)",
1285 mark->val, mark->mask, mark->success);
1293 for (i = 0; i < sel->nkeys; i++) {
1294 show_keys(f, sel->keys + i);
1295 if (show_stats && NULL != pf)
1296 fprintf(f, " (success %llu ) ",
1297 (unsigned long long) pf->kcnts[i]);
1301 if (sel->flags & (TC_U32_VAROFFSET | TC_U32_OFFSET)) {
1302 fprintf(f, "\n offset ");
1303 if (sel->flags & TC_U32_VAROFFSET)
1304 fprintf(f, "%04x>>%d at %d ",
1305 ntohs(sel->offmask),
1306 sel->offshift, sel->offoff);
1308 fprintf(f, "plus %d ", sel->off);
1310 if (sel->flags & TC_U32_EAT)
1311 fprintf(f, " eat ");
1314 fprintf(f, "\n hash mask %08x at %d ",
1315 (unsigned int)htonl(sel->hmask), sel->hoff);
1319 if (tb[TCA_U32_POLICE]) {
1321 tc_print_police(f, tb[TCA_U32_POLICE]);
1324 if (tb[TCA_U32_INDEV]) {
1325 struct rtattr *idev = tb[TCA_U32_INDEV];
1327 fprintf(f, "\n input dev %s\n", rta_getattr_str(idev));
1330 if (tb[TCA_U32_ACT])
1331 tc_print_action(f, tb[TCA_U32_ACT], 0);
1336 struct filter_util u32_filter_util = {
1338 .parse_fopt = u32_parse_opt,
1339 .print_fopt = u32_print_opt,