]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - tc/f_u32.c
479b3f1bb8587b256b81816773e7f763e8b9c3a7
[lisovros/iproute2_canprio.git] / tc / f_u32.c
1 /*
2  * q_u32.c              U32 filter.
3  *
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.
8  *
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]
11  *
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <syslog.h>
18 #include <fcntl.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <string.h>
23 #include <linux/if.h>
24 #include <linux/if_ether.h>
25
26 #include "utils.h"
27 #include "tc_util.h"
28
29 extern int show_pretty;
30
31 static void explain(void)
32 {
33         fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ]"
34                 " [ classid CLASSID ]\n");
35         fprintf(stderr, "               [ police POLICE_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");
46 }
47
48 int get_u32_handle(__u32 *handle, const char *str)
49 {
50         __u32 htid=0, hash=0, nodeid=0;
51         char *tmp = strchr(str, ':');
52
53         if (tmp == NULL) {
54                 if (memcmp("0x", str, 2) == 0)
55                         return get_u32(handle, str, 16);
56                 return -1;
57         }
58         htid = strtoul(str, &tmp, 16);
59         if (tmp == str && *str != ':' && *str != 0)
60                 return -1;
61         if (htid>=0x1000)
62                 return -1;
63         if (*tmp) {
64                 str = tmp+1;
65                 hash = strtoul(str, &tmp, 16);
66                 if (tmp == str && *str != ':' && *str != 0)
67                         return -1;
68                 if (hash>=0x100)
69                         return -1;
70                 if (*tmp) {
71                         str = tmp+1;
72                         nodeid = strtoul(str, &tmp, 16);
73                         if (tmp == str && *str != 0)
74                                 return -1;
75                         if (nodeid>=0x1000)
76                                 return -1;
77                 }
78         }
79         *handle = (htid<<20)|(hash<<12)|nodeid;
80         return 0;
81 }
82
83 char * sprint_u32_handle(__u32 handle, char *buf)
84 {
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);
89         char *b = buf;
90
91         if (handle == 0) {
92                 snprintf(b, bsize, "none");
93                 return b;
94         }
95         if (htid) {
96                 int l = snprintf(b, bsize, "%x:", htid>>20);
97                 bsize -= l;
98                 b += l;
99         }
100         if (nodeid|hash) {
101                 if (hash) {
102                         int l = snprintf(b, bsize, "%x", hash);
103                         bsize -= l;
104                         b += l;
105                 }
106                 if (nodeid) {
107                         int l = snprintf(b, bsize, ":%x", nodeid);
108                         bsize -= l;
109                         b += l;
110                 }
111         }
112         if (show_raw)
113                 snprintf(b, bsize, "[%08x] ", handle);
114         return buf;
115 }
116
117 static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
118                     int off, int offmask)
119 {
120         int i;
121         int hwm = sel->nkeys;
122
123         key &= mask;
124
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;
128
129                         if ((key^sel->keys[i].val) & intersect)
130                                 return -1;
131                         sel->keys[i].val |= key;
132                         sel->keys[i].mask |= mask;
133                         return 0;
134                 }
135         }
136
137         if (hwm >= 128)
138                 return -1;
139         if (off % 4)
140                 return -1;
141         sel->keys[hwm].val = key;
142         sel->keys[hwm].mask = mask;
143         sel->keys[hwm].off = off;
144         sel->keys[hwm].offmask = offmask;
145         sel->nkeys++;
146         return 0;
147 }
148
149 static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
150                       int off, int offmask)
151 {
152         key = htonl(key);
153         mask = htonl(mask);
154         return pack_key(sel, key, mask, off, offmask);
155 }
156
157 static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
158                       int off, int offmask)
159 {
160         if (key > 0xFFFF || mask > 0xFFFF)
161                 return -1;
162
163         if ((off & 3) == 0) {
164                 key <<= 16;
165                 mask <<= 16;
166         }
167         off &= ~3;
168         key = htonl(key);
169         mask = htonl(mask);
170
171         return pack_key(sel, key, mask, off, offmask);
172 }
173
174 static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
175 {
176         if (key > 0xFF || mask > 0xFF)
177                 return -1;
178
179         if ((off & 3) == 0) {
180                 key <<= 24;
181                 mask <<= 24;
182         } else if ((off & 3) == 1) {
183                 key <<= 16;
184                 mask <<= 16;
185         } else if ((off & 3) == 2) {
186                 key <<= 8;
187                 mask <<= 8;
188         }
189         off &= ~3;
190         key = htonl(key);
191         mask = htonl(mask);
192
193         return pack_key(sel, key, mask, off, offmask);
194 }
195
196
197 int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
198 {
199         int argc = *argc_p;
200         char **argv = *argv_p;
201         char *p = *argv;
202
203         if (argc <= 0)
204                 return -1;
205
206         if (strlen(p) > strlen("nexthdr+") &&
207             memcmp(p, "nexthdr+", strlen("nexthdr+")) == 0) {
208                 *offmask = -1;
209                 p += strlen("nexthdr+");
210         } else if (matches(*argv, "nexthdr+") == 0) {
211                 NEXT_ARG();
212                 *offmask = -1;
213                 p = *argv;
214         }
215
216         if (get_integer(off, p, 0))
217                 return -1;
218         argc--; argv++;
219
220         *argc_p = argc;
221         *argv_p = argv;
222         return 0;
223 }
224
225
226 static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
227                      int off, int offmask)
228 {
229         int res = -1;
230         int argc = *argc_p;
231         char **argv = *argv_p;
232         __u32 key;
233         __u32 mask;
234
235         if (argc < 2)
236                 return -1;
237
238         if (get_u32(&key, *argv, 0))
239                 return -1;
240         argc--; argv++;
241
242         if (get_u32(&mask, *argv, 16))
243                 return -1;
244         argc--; argv++;
245
246         if (argc > 0 && strcmp(argv[0], "at") == 0) {
247                 NEXT_ARG();
248                 if (parse_at(&argc, &argv, &off, &offmask))
249                         return -1;
250         }
251
252         res = pack_key32(sel, key, mask, off, offmask);
253         *argc_p = argc;
254         *argv_p = argv;
255         return res;
256 }
257
258 static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
259                      int off, int offmask)
260 {
261         int res = -1;
262         int argc = *argc_p;
263         char **argv = *argv_p;
264         __u32 key;
265         __u32 mask;
266
267         if (argc < 2)
268                 return -1;
269
270         if (get_u32(&key, *argv, 0))
271                 return -1;
272         argc--; argv++;
273
274         if (get_u32(&mask, *argv, 16))
275                 return -1;
276         argc--; argv++;
277
278         if (argc > 0 && strcmp(argv[0], "at") == 0) {
279                 NEXT_ARG();
280                 if (parse_at(&argc, &argv, &off, &offmask))
281                         return -1;
282         }
283         res = pack_key16(sel, key, mask, off, offmask);
284         *argc_p = argc;
285         *argv_p = argv;
286         return res;
287 }
288
289 static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
290                     int off, int offmask)
291 {
292         int res = -1;
293         int argc = *argc_p;
294         char **argv = *argv_p;
295         __u32 key;
296         __u32 mask;
297
298         if (argc < 2)
299                 return -1;
300
301         if (get_u32(&key, *argv, 0))
302                 return -1;
303         argc--; argv++;
304
305         if (get_u32(&mask, *argv, 16))
306                 return -1;
307         argc--; argv++;
308
309         if (key > 0xFF || mask > 0xFF)
310                 return -1;
311
312         if (argc > 0 && strcmp(argv[0], "at") == 0) {
313                 NEXT_ARG();
314                 if (parse_at(&argc, &argv, &off, &offmask))
315                         return -1;
316         }
317
318         res = pack_key8(sel, key, mask, off, offmask);
319         *argc_p = argc;
320         *argv_p = argv;
321         return res;
322 }
323
324 static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
325                          int off)
326 {
327         int res = -1;
328         int argc = *argc_p;
329         char **argv = *argv_p;
330         inet_prefix addr;
331         __u32 mask;
332         int offmask = 0;
333
334         if (argc < 1)
335                 return -1;
336
337         if (get_prefix_1(&addr, *argv, AF_INET))
338                 return -1;
339         argc--; argv++;
340
341         if (argc > 0 && strcmp(argv[0], "at") == 0) {
342                 NEXT_ARG();
343                 if (parse_at(&argc, &argv, &off, &offmask))
344                         return -1;
345         }
346
347         mask = 0;
348         if (addr.bitlen)
349                 mask = htonl(0xFFFFFFFF<<(32-addr.bitlen));
350         if (pack_key(sel, addr.data[0], mask, off, offmask) < 0)
351                 return -1;
352         res = 0;
353
354         *argc_p = argc;
355         *argv_p = argv;
356         return res;
357 }
358
359 static int parse_ip6_addr(int *argc_p, char ***argv_p,
360                           struct tc_u32_sel *sel, int off)
361 {
362         int res = -1;
363         int argc = *argc_p;
364         char **argv = *argv_p;
365         int plen = 128;
366         int i;
367         inet_prefix addr;
368         int offmask = 0;
369
370         if (argc < 1)
371                 return -1;
372
373         if (get_prefix_1(&addr, *argv, AF_INET6))
374                 return -1;
375         argc--; argv++;
376
377         if (argc > 0 && strcmp(argv[0], "at") == 0) {
378                 NEXT_ARG();
379                 if (parse_at(&argc, &argv, &off, &offmask))
380                         return -1;
381         }
382
383         plen = addr.bitlen;
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);
389                         if (res < 0)
390                                 return -1;
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);
395                         if (res < 0)
396                                 return -1;
397                 }
398         }
399         res = 0;
400
401         *argc_p = argc;
402         *argv_p = argv;
403         return res;
404 }
405
406 static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
407 {
408         int res = -1;
409         int argc = *argc_p;
410         char **argv = *argv_p;
411         __u32 key;
412         __u32 mask;
413         int off = 0;
414         int offmask = 0;
415
416         if (argc < 2)
417                 return -1;
418
419         if (get_u32(&key, *argv, 0))
420                 return -1;
421         argc--; argv++;
422
423         if (get_u32(&mask, *argv, 16))
424                 return -1;
425         argc--; argv++;
426
427         if (key > 0xFF || mask > 0xFF)
428                 return -1;
429
430         key <<= 20;
431         mask <<= 20;
432         key = htonl(key);
433         mask = htonl(mask);
434
435         res = pack_key(sel, key, mask, off, offmask);
436         if (res < 0)
437                 return -1;
438
439         *argc_p = argc;
440         *argv_p = argv;
441         return 0;
442 }
443
444 static int parse_ether_addr(int *argc_p, char ***argv_p,
445                             struct tc_u32_sel *sel, int off)
446 {
447         int res = -1;
448         int argc = *argc_p;
449         char **argv = *argv_p;
450         __u8 addr[6];
451         int offmask = 0;
452         int i;
453
454         if (argc < 1)
455                 return -1;
456
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",
461                         *argv);
462                 return -1;
463         }
464
465         argc--; argv++;
466         if (argc > 0 && strcmp(argv[0], "at") == 0) {
467                 NEXT_ARG();
468                 if (parse_at(&argc, &argv, &off, &offmask))
469                         return -1;
470         }
471
472         for (i = 0; i < 6; i++) {
473                 res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
474                 if (res < 0)
475                         return -1;
476         }
477
478         *argc_p = argc;
479         *argv_p = argv;
480         return res;
481 }
482
483 static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
484 {
485         int res = -1;
486         int argc = *argc_p;
487         char **argv = *argv_p;
488
489         if (argc < 2)
490                 return -1;
491
492         if (strcmp(*argv, "src") == 0) {
493                 NEXT_ARG();
494                 res = parse_ip_addr(&argc, &argv, sel, 12);
495         } else if (strcmp(*argv, "dst") == 0) {
496                 NEXT_ARG();
497                 res = parse_ip_addr(&argc, &argv, sel, 16);
498         } else if (strcmp(*argv, "tos") == 0 ||
499             matches(*argv, "dsfield") == 0) {
500                 NEXT_ARG();
501                 res = parse_u8(&argc, &argv, sel, 1, 0);
502         } else if (strcmp(*argv, "ihl") == 0) {
503                 NEXT_ARG();
504                 res = parse_u8(&argc, &argv, sel, 0, 0);
505         } else if (strcmp(*argv, "protocol") == 0) {
506                 NEXT_ARG();
507                 res = parse_u8(&argc, &argv, sel, 9, 0);
508         } else if (matches(*argv, "precedence") == 0) {
509                 NEXT_ARG();
510                 res = parse_u8(&argc, &argv, sel, 1, 0);
511         } else if (strcmp(*argv, "nofrag") == 0) {
512                 argc--; argv++;
513                 res = pack_key16(sel, 0, 0x3FFF, 6, 0);
514         } else if (strcmp(*argv, "firstfrag") == 0) {
515                 argc--; argv++;
516                 res = pack_key16(sel, 0, 0x1FFF, 6, 0);
517         } else if (strcmp(*argv, "df") == 0) {
518                 argc--; argv++;
519                 res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
520         } else if (strcmp(*argv, "mf") == 0) {
521                 argc--; argv++;
522                 res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
523         } else if (strcmp(*argv, "dport") == 0) {
524                 NEXT_ARG();
525                 res = parse_u16(&argc, &argv, sel, 22, 0);
526         } else if (strcmp(*argv, "sport") == 0) {
527                 NEXT_ARG();
528                 res = parse_u16(&argc, &argv, sel, 20, 0);
529         } else if (strcmp(*argv, "icmp_type") == 0) {
530                 NEXT_ARG();
531                 res = parse_u8(&argc, &argv, sel, 20, 0);
532         } else if (strcmp(*argv, "icmp_code") == 0) {
533                 NEXT_ARG();
534                 res = parse_u8(&argc, &argv, sel, 20, 1);
535         } else
536                 return -1;
537
538         *argc_p = argc;
539         *argv_p = argv;
540         return res;
541 }
542                                 
543 static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
544 {
545         int res = -1;
546         int argc = *argc_p;
547         char **argv = *argv_p;
548
549         if (argc < 2)
550                 return -1;
551
552         if (strcmp(*argv, "src") == 0) {
553                 NEXT_ARG();
554                 res = parse_ip6_addr(&argc, &argv, sel, 8);
555         } else if (strcmp(*argv, "dst") == 0) {
556                 NEXT_ARG();
557                 res = parse_ip6_addr(&argc, &argv, sel, 24);
558         } else if (strcmp(*argv, "priority") == 0) {
559                 NEXT_ARG();
560                 res = parse_ip6_class(&argc, &argv, sel);
561         } else if (strcmp(*argv, "protocol") == 0) {
562                 NEXT_ARG();
563                 res = parse_u8(&argc, &argv, sel, 6, 0);
564         } else if (strcmp(*argv, "flowlabel") == 0) {
565                 NEXT_ARG();
566                 res = parse_u32(&argc, &argv, sel, 0, 0);
567         } else if (strcmp(*argv, "dport") == 0) {
568                 NEXT_ARG();
569                 res = parse_u16(&argc, &argv, sel, 42, 0);
570         } else if (strcmp(*argv, "sport") == 0) {
571                 NEXT_ARG();
572                 res = parse_u16(&argc, &argv, sel, 40, 0);
573         } else if (strcmp(*argv, "icmp_type") == 0) {
574                 NEXT_ARG();
575                 res = parse_u8(&argc, &argv, sel, 40, 0);
576         } else if (strcmp(*argv, "icmp_code") == 0) {
577                 NEXT_ARG();
578                 res = parse_u8(&argc, &argv, sel, 41, 1);
579         } else
580                 return -1;
581
582         *argc_p = argc;
583         *argv_p = argv;
584         return res;
585 }
586
587 static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
588 {
589         int res = -1;
590         int argc = *argc_p;
591         char **argv = *argv_p;
592
593         if (argc < 2)
594                 return -1;
595
596         if (strcmp(*argv, "src") == 0) {
597                 NEXT_ARG();
598                 res = parse_ether_addr(&argc, &argv, sel, -8);
599         } else if (strcmp(*argv, "dst") == 0) {
600                 NEXT_ARG();
601                 res = parse_ether_addr(&argc, &argv, sel, -14);
602         } else {
603                 fprintf(stderr, "Unknown match: ether %s\n", *argv);
604                 return -1;
605         }
606
607         *argc_p = argc;
608         *argv_p = argv;
609         return res;
610 }
611
612 #define parse_tcp parse_udp
613 static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
614 {
615         int res = -1;
616         int argc = *argc_p;
617         char **argv = *argv_p;
618
619         if (argc < 2)
620                 return -1;
621
622         if (strcmp(*argv, "src") == 0) {
623                 NEXT_ARG();
624                 res = parse_u16(&argc, &argv, sel, 0, -1);
625         } else if (strcmp(*argv, "dst") == 0) {
626                 NEXT_ARG();
627                 res = parse_u16(&argc, &argv, sel, 2, -1);
628         } else
629                 return -1;
630
631         *argc_p = argc;
632         *argv_p = argv;
633         return res;
634 }
635
636
637 static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
638 {
639         int res = -1;
640         int argc = *argc_p;
641         char **argv = *argv_p;
642
643         if (argc < 2)
644                 return -1;
645
646         if (strcmp(*argv, "type") == 0) {
647                 NEXT_ARG();
648                 res = parse_u8(&argc, &argv, sel, 0, -1);
649         } else if (strcmp(*argv, "code") == 0) {
650                 NEXT_ARG();
651                 res = parse_u8(&argc, &argv, sel, 1, -1);
652         } else
653                 return -1;
654
655         *argc_p = argc;
656         *argv_p = argv;
657         return res;
658 }
659
660 static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
661 {
662         int res = -1;
663         int argc = *argc_p;
664         char **argv = *argv_p;
665         struct tc_u32_mark mark;
666
667         if (argc <= 1)
668                 return -1;
669
670         if (get_u32(&mark.val, *argv, 0)) {
671                 fprintf(stderr, "Illegal \"mark\" value\n");
672                 return -1;
673         }
674         NEXT_ARG();
675
676         if (get_u32(&mark.mask, *argv, 0)) {
677                 fprintf(stderr, "Illegal \"mark\" mask\n");
678                 return -1;
679         }
680         NEXT_ARG();
681
682         if ((mark.val & mark.mask) != mark.val) {
683                 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
684                 return -1;
685         }
686
687         addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
688         res = 0;
689
690         *argc_p = argc;
691         *argv_p = argv;
692         return res;
693 }
694
695 static int parse_selector(int *argc_p, char ***argv_p,
696                           struct tc_u32_sel *sel, struct nlmsghdr *n)
697 {
698         int argc = *argc_p;
699         char **argv = *argv_p;
700         int res = -1;
701
702         if (argc <= 0)
703                 return -1;
704
705         if (matches(*argv, "u32") == 0) {
706                 NEXT_ARG();
707                 res = parse_u32(&argc, &argv, sel, 0, 0);
708         } else if (matches(*argv, "u16") == 0) {
709                 NEXT_ARG();
710                 res = parse_u16(&argc, &argv, sel, 0, 0);
711         } else if (matches(*argv, "u8") == 0) {
712                 NEXT_ARG();
713                 res = parse_u8(&argc, &argv, sel, 0, 0);
714         } else if (matches(*argv, "ip") == 0) {
715                 NEXT_ARG();
716                 res = parse_ip(&argc, &argv, sel);
717         } else  if (matches(*argv, "ip6") == 0) {
718                 NEXT_ARG();
719                 res = parse_ip6(&argc, &argv, sel);
720         } else if (matches(*argv, "udp") == 0) {
721                 NEXT_ARG();
722                 res = parse_udp(&argc, &argv, sel);
723         } else if (matches(*argv, "tcp") == 0) {
724                 NEXT_ARG();
725                 res = parse_tcp(&argc, &argv, sel);
726         } else if (matches(*argv, "icmp") == 0) {
727                 NEXT_ARG();
728                 res = parse_icmp(&argc, &argv, sel);
729         } else if (matches(*argv, "mark") == 0) {
730                 NEXT_ARG();
731                 res = parse_mark(&argc, &argv, n);
732         } else if (matches(*argv, "ether") == 0) {
733                 NEXT_ARG();
734                 res = parse_ether(&argc, &argv, sel);
735         } else 
736                 return -1;
737
738         *argc_p = argc;
739         *argv_p = argv;
740         return res;
741 }
742
743 static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
744 {
745         int argc = *argc_p;
746         char **argv = *argv_p;
747
748         while (argc > 0) {
749                 if (matches(*argv, "plus") == 0) {
750                         int off;
751                         NEXT_ARG();
752                         if (get_integer(&off, *argv, 0))
753                                 return -1;
754                         sel->off = off;
755                         sel->flags |= TC_U32_OFFSET;
756                 } else if (matches(*argv, "at") == 0) {
757                         int off;
758                         NEXT_ARG();
759                         if (get_integer(&off, *argv, 0))
760                                 return -1;
761                         sel->offoff = off;
762                         if (off%2) {
763                                 fprintf(stderr, "offset \"at\" must be even\n");
764                                 return -1;
765                         }
766                         sel->flags |= TC_U32_VAROFFSET;
767                 } else if (matches(*argv, "mask") == 0) {
768                         __u16 mask;
769                         NEXT_ARG();
770                         if (get_u16(&mask, *argv, 16))
771                                 return -1;
772                         sel->offmask = htons(mask);
773                         sel->flags |= TC_U32_VAROFFSET;
774                 } else if (matches(*argv, "shift") == 0) {
775                         int shift;
776                         NEXT_ARG();
777                         if (get_integer(&shift, *argv, 0))
778                                 return -1;
779                         sel->offshift = shift;
780                         sel->flags |= TC_U32_VAROFFSET;
781                 } else if (matches(*argv, "eat") == 0) {
782                         sel->flags |= TC_U32_EAT;
783                 } else {
784                         break;
785                 }
786                 argc--; argv++;
787         }
788
789         *argc_p = argc;
790         *argv_p = argv;
791         return 0;
792 }
793
794 static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
795 {
796         int argc = *argc_p;
797         char **argv = *argv_p;
798
799         while (argc > 0) {
800                 if (matches(*argv, "mask") == 0) {
801                         __u32 mask;
802                         NEXT_ARG();
803                         if (get_u32(&mask, *argv, 16))
804                                 return -1;
805                         sel->hmask = htonl(mask);
806                 } else if (matches(*argv, "at") == 0) {
807                         int num;
808                         NEXT_ARG();
809                         if (get_integer(&num, *argv, 0))
810                                 return -1;
811                         if (num%4)
812                                 return -1;
813                         sel->hoff = num;
814                 } else {
815                         break;
816                 }
817                 argc--; argv++;
818         }
819
820         *argc_p = argc;
821         *argv_p = argv;
822         return 0;
823 }
824
825 static void print_ipv4(FILE *f, const struct tc_u32_key *key)
826 {
827         char abuf[256];
828
829         switch (key->off) {
830         case 0:
831                 switch (ntohl(key->mask)) {
832                 case 0x0f000000:
833                         fprintf(f, "\n  match IP ihl %u", ntohl(key->val) >> 24);
834                         return;
835                 case 0x00ff0000:
836                         fprintf(f, "\n  match IP dsfield %#x", ntohl(key->val) >> 16);
837                         return;
838                 }
839                 break;
840         case 8:
841                 if (ntohl(key->mask) == 0x00ff0000) {
842                         fprintf(f, "\n  match IP protocol %d", ntohl(key->val) >> 16);
843                         return;
844                 }
845                 break;
846         case 12:
847         case 16: {
848                         int bits = mask2bits(key->mask);
849                         if (bits >= 0) {
850                                 fprintf(f, "\n  %s %s/%d", 
851                                         key->off == 12 ? "match IP src" : "match IP dst",
852                                         inet_ntop(AF_INET, &key->val,
853                                                   abuf, sizeof(abuf)),
854                                         bits);
855                                 return;
856                         }
857                 }
858                 break;
859
860         case 20:
861                 switch (ntohl(key->mask)) {
862                 case 0x0000ffff:
863                         fprintf(f, "\n  match dport %u",
864                                 ntohl(key->val) & 0xffff);
865                         return;
866                 case 0xffff0000:
867                         fprintf(f, "\n  match sport %u",
868                                 ntohl(key->val) >> 16);
869                         return;
870                 case 0xffffffff:
871                         fprintf(f, "\n  match dport %u, match sport %u",
872                                 ntohl(key->val) & 0xffff,
873                                 ntohl(key->val) >> 16);
874
875                         return;
876                 }
877                 /* XXX: Default print_raw */
878         }
879 }
880
881 static void print_ipv6(FILE *f, const struct tc_u32_key *key)
882 {
883         char abuf[256];
884
885         switch (key->off) {
886         case 0:
887                 switch (ntohl(key->mask)) {
888                 case 0x0f000000:
889                         fprintf(f, "\n  match IP ihl %u", ntohl(key->val) >> 24);
890                         return;
891                 case 0x00ff0000:
892                         fprintf(f, "\n  match IP dsfield %#x", ntohl(key->val) >> 16);
893                         return;
894                 }
895                 break;
896         case 8:
897                 if (ntohl(key->mask) == 0x00ff0000) {
898                         fprintf(f, "\n  match IP protocol %d", ntohl(key->val) >> 16);
899                         return;
900                 }
901                 break;
902         case 12:
903         case 16: {
904                         int bits = mask2bits(key->mask);
905                         if (bits >= 0) {
906                                 fprintf(f, "\n  %s %s/%d", 
907                                         key->off == 12 ? "match IP src" : "match IP dst",
908                                         inet_ntop(AF_INET, &key->val,
909                                                   abuf, sizeof(abuf)),
910                                         bits);
911                                 return;
912                         }
913                 }
914                 break;
915
916         case 20:
917                 switch (ntohl(key->mask)) {
918                 case 0x0000ffff:
919                         fprintf(f, "\n  match sport %u",
920                                 ntohl(key->val) & 0xffff);
921                         return;
922                 case 0xffff0000:
923                         fprintf(f, "\n  match dport %u",
924                                 ntohl(key->val) >> 16);
925                         return;
926                 case 0xffffffff:
927                         fprintf(f, "\n  match sport %u, match dport %u",
928                                 ntohl(key->val) & 0xffff,
929                                 ntohl(key->val) >> 16);
930
931                         return;
932                 }
933                 /* XXX: Default print_raw */
934         }
935 }
936
937 static void print_raw(FILE *f, const struct tc_u32_key *key)
938 {
939         fprintf(f, "\n  match %08x/%08x at %s%d", 
940                 (unsigned int)ntohl(key->val),
941                 (unsigned int)ntohl(key->mask),
942                 key->offmask ? "nexthdr+" : "",
943                 key->off);
944 }
945
946 static const struct {
947         __u16 proto;
948         __u16 pad;
949         void (*pprinter)(FILE *f, const struct tc_u32_key *key);
950 } u32_pprinters[] = {
951         {0,        0, print_raw},
952         {ETH_P_IP, 0, print_ipv4},
953         {ETH_P_IPV6, 0, print_ipv6},
954 };
955
956 static void show_keys(FILE *f, const struct tc_u32_key *key)
957 {
958         int i = 0;
959
960         if (!show_pretty)
961                 goto show_k;
962
963         for (i = 0; i < sizeof(u32_pprinters) / sizeof(u32_pprinters[0]); i++) {
964                 if (u32_pprinters[i].proto == ntohs(f_proto)) {
965 show_k:
966                         u32_pprinters[i].pprinter(f, key);
967                         return;
968                 }
969         }
970
971         i = 0;
972         goto show_k;
973 }
974
975 static int u32_parse_opt(struct filter_util *qu, char *handle,
976                          int argc, char **argv, struct nlmsghdr *n)
977 {
978         struct {
979                 struct tc_u32_sel sel;
980                 struct tc_u32_key keys[128];
981         } sel;
982         struct tcmsg *t = NLMSG_DATA(n);
983         struct rtattr *tail;
984         int sel_ok = 0, terminal_ok = 0;
985         int sample_ok = 0;
986         __u32 htid = 0;
987         __u32 order = 0;
988
989         memset(&sel, 0, sizeof(sel));
990
991         if (handle && get_u32_handle(&t->tcm_handle, handle)) {
992                 fprintf(stderr, "Illegal filter ID\n");
993                 return -1;
994         }
995
996         if (argc == 0)
997                 return 0;
998
999         tail = NLMSG_TAIL(n);
1000         addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
1001
1002         while (argc > 0) {
1003                 if (matches(*argv, "match") == 0) {
1004                         NEXT_ARG();
1005                         if (parse_selector(&argc, &argv, &sel.sel, n)) {
1006                                 fprintf(stderr, "Illegal \"match\"\n");
1007                                 return -1;
1008                         }
1009                         sel_ok++;
1010                         continue;
1011                 } else if (matches(*argv, "offset") == 0) {
1012                         NEXT_ARG();
1013                         if (parse_offset(&argc, &argv, &sel.sel)) {
1014                                 fprintf(stderr, "Illegal \"offset\"\n");
1015                                 return -1;
1016                         }
1017                         continue;
1018                 } else if (matches(*argv, "hashkey") == 0) {
1019                         NEXT_ARG();
1020                         if (parse_hashkey(&argc, &argv, &sel.sel)) {
1021                                 fprintf(stderr, "Illegal \"hashkey\"\n");
1022                                 return -1;
1023                         }
1024                         continue;
1025                 } else if (matches(*argv, "classid") == 0 ||
1026                            strcmp(*argv, "flowid") == 0) {
1027                         unsigned handle;
1028                         NEXT_ARG();
1029                         if (get_tc_classid(&handle, *argv)) {
1030                                 fprintf(stderr, "Illegal \"classid\"\n");
1031                                 return -1;
1032                         }
1033                         addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4);
1034                         sel.sel.flags |= TC_U32_TERMINAL;
1035                 } else if (matches(*argv, "divisor") == 0) {
1036                         unsigned divisor;
1037                         NEXT_ARG();
1038                         if (get_unsigned(&divisor, *argv, 0) ||
1039                             divisor == 0 ||
1040                             divisor > 0x100 || ((divisor - 1) & divisor)) {
1041                                 fprintf(stderr, "Illegal \"divisor\"\n");
1042                                 return -1;
1043                         }
1044                         addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
1045                 } else if (matches(*argv, "order") == 0) {
1046                         NEXT_ARG();
1047                         if (get_u32(&order, *argv, 0)) {
1048                                 fprintf(stderr, "Illegal \"order\"\n");
1049                                 return -1;
1050                         }
1051                 } else if (strcmp(*argv, "link") == 0) {
1052                         unsigned handle;
1053                         NEXT_ARG();
1054                         if (get_u32_handle(&handle, *argv)) {
1055                                 fprintf(stderr, "Illegal \"link\"\n");
1056                                 return -1;
1057                         }
1058                         if (handle && TC_U32_NODE(handle)) {
1059                                 fprintf(stderr, "\"link\" must be a hash table.\n");
1060                                 return -1;
1061                         }
1062                         addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4);
1063                 } else if (strcmp(*argv, "ht") == 0) {
1064                         unsigned handle;
1065                         NEXT_ARG();
1066                         if (get_u32_handle(&handle, *argv)) {
1067                                 fprintf(stderr, "Illegal \"ht\"\n");
1068                                 return -1;
1069                         }
1070                         if (handle && TC_U32_NODE(handle)) {
1071                                 fprintf(stderr, "\"ht\" must be a hash table.\n");
1072                                 return -1;
1073                         }
1074                         if (sample_ok)
1075                                 htid = (htid&0xFF000)|(handle&0xFFF00000);
1076                         else
1077                                 htid = (handle&0xFFFFF000);
1078                 } else if (strcmp(*argv, "sample") == 0) {
1079                         __u32 hash;
1080                         unsigned divisor = 0x100;
1081
1082                         struct {
1083                                 struct tc_u32_sel sel;
1084                                 struct tc_u32_key keys[4];
1085                         } sel2;
1086                         memset(&sel2, 0, sizeof(sel2));
1087                         NEXT_ARG();
1088                         if (parse_selector(&argc, &argv, &sel2.sel, n)) {
1089                                 fprintf(stderr, "Illegal \"sample\"\n");
1090                                 return -1;
1091                         }
1092                         if (sel2.sel.nkeys != 1) {
1093                                 fprintf(stderr, "\"sample\" must contain"
1094                                         " exactly ONE key.\n");
1095                                 return -1;
1096                         }
1097                         if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1098                                 NEXT_ARG();
1099                                 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
1100                                     divisor > 0x100 || ((divisor - 1) & divisor)) {
1101                                         fprintf(stderr, "Illegal sample \"divisor\"\n");
1102                                         return -1;
1103                                 }
1104                                 NEXT_ARG();
1105                         }
1106                         hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask;
1107                         hash ^= hash>>16;
1108                         hash ^= hash>>8;
1109                         htid = ((hash%divisor)<<12)|(htid&0xFFF00000);
1110                         sample_ok = 1;
1111                         continue;
1112                 } else if (strcmp(*argv, "indev") == 0) {
1113                         char ind[IFNAMSIZ + 1];
1114                         memset(ind, 0, sizeof (ind));
1115                         argc--;
1116                         argv++;
1117                         if (argc < 1) {
1118                                 fprintf(stderr, "Illegal indev\n");
1119                                 return -1;
1120                         }
1121                         strncpy(ind, *argv, sizeof (ind) - 1);
1122                         addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1);
1123
1124                 } else if (matches(*argv, "action") == 0) {
1125                         NEXT_ARG();
1126                         if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1127                                 fprintf(stderr, "Illegal \"action\"\n");
1128                                 return -1;
1129                         }
1130                         terminal_ok++;
1131                         continue;
1132
1133                 } else if (matches(*argv, "police") == 0) {
1134                         NEXT_ARG();
1135                         if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1136                                 fprintf(stderr, "Illegal \"police\"\n");
1137                                 return -1;
1138                         }
1139                         terminal_ok++;
1140                         continue;
1141                 } else if (strcmp(*argv, "help") == 0) {
1142                         explain();
1143                         return -1;
1144                 } else {
1145                         fprintf(stderr, "What is \"%s\"?\n", *argv);
1146                         explain();
1147                         return -1;
1148                 }
1149                 argc--; argv++;
1150         }
1151
1152         /* We dont necessarily need class/flowids */
1153         if (terminal_ok)
1154                 sel.sel.flags |= TC_U32_TERMINAL;
1155         
1156         if (order) {
1157                 if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
1158                         fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1159                         return -1;
1160                 }
1161                 t->tcm_handle |= order;
1162         }
1163
1164         if (htid)
1165                 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
1166         if (sel_ok)
1167                 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, 
1168                           sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
1169         tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
1170         return 0;
1171 }
1172
1173 static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1174                          __u32 handle)
1175 {
1176         struct rtattr *tb[TCA_U32_MAX+1];
1177         struct tc_u32_sel *sel = NULL;
1178         struct tc_u32_pcnt *pf = NULL;
1179
1180         if (opt == NULL)
1181                 return 0;
1182
1183         parse_rtattr_nested(tb, TCA_U32_MAX, opt);
1184
1185         if (handle) {
1186                 SPRINT_BUF(b1);
1187                 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1188         }
1189         if (TC_U32_NODE(handle)) {
1190                 fprintf(f, "order %d ", TC_U32_NODE(handle));
1191         }
1192
1193         if (tb[TCA_U32_SEL]) {
1194                 if (RTA_PAYLOAD(tb[TCA_U32_SEL])  < sizeof(*sel))
1195                         return -1;
1196
1197                 sel = RTA_DATA(tb[TCA_U32_SEL]);
1198         }
1199
1200         if (tb[TCA_U32_DIVISOR]) {
1201                 fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR]));
1202         } else if (tb[TCA_U32_HASH]) {
1203                 __u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]);
1204                 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1205                         TC_U32_HASH(htid));
1206         } else {
1207                 fprintf(f, "??? ");
1208         }
1209         if (tb[TCA_U32_CLASSID]) {
1210                 SPRINT_BUF(b1);
1211                 fprintf(f, "%sflowid %s ",
1212                         !sel || !(sel->flags&TC_U32_TERMINAL) ? "*" : "",
1213                         sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_U32_CLASSID]), b1));
1214         } else if (sel && sel->flags&TC_U32_TERMINAL) {
1215                 fprintf(f, "terminal flowid ??? ");
1216         }
1217         if (tb[TCA_U32_LINK]) {
1218                 SPRINT_BUF(b1);
1219                 fprintf(f, "link %s ",
1220                         sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
1221         }
1222
1223         if (tb[TCA_U32_PCNT]) {
1224                 if (RTA_PAYLOAD(tb[TCA_U32_PCNT])  < sizeof(*pf)) {
1225                         fprintf(f, "Broken perf counters \n");
1226                         return -1;
1227                 }
1228                 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1229         }
1230
1231         if (sel && show_stats && NULL != pf)
1232                 fprintf(f, " (rule hit %llu success %llu)",
1233                         (unsigned long long) pf->rcnt,
1234                         (unsigned long long) pf->rhit);
1235
1236         if (tb[TCA_U32_MARK]) {
1237                 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1238                 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1239                         fprintf(f, "\n  Invalid mark (kernel&iproute2 mismatch)\n");
1240                 } else {
1241                         fprintf(f, "\n  mark 0x%04x 0x%04x (success %d)",
1242                                 mark->val, mark->mask, mark->success);
1243                 }
1244         }
1245
1246         if (sel) {
1247                 if (sel->nkeys) {
1248                         int i;
1249                         for (i=0; i<sel->nkeys; i++) {
1250                                 show_keys(f, sel->keys + i);
1251                                 if (show_stats && NULL != pf)
1252                                         fprintf(f, " (success %llu ) ",
1253                                                 (unsigned long long) pf->kcnts[i]);
1254                         }
1255                 }
1256
1257                 if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) {
1258                         fprintf(f, "\n    offset ");
1259                         if (sel->flags&TC_U32_VAROFFSET)
1260                                 fprintf(f, "%04x>>%d at %d ",
1261                                         ntohs(sel->offmask),
1262                                         sel->offshift,  sel->offoff);
1263                         if (sel->off)
1264                                 fprintf(f, "plus %d ", sel->off);
1265                 }
1266                 if (sel->flags&TC_U32_EAT)
1267                         fprintf(f, " eat ");
1268
1269                 if (sel->hmask) {
1270                         fprintf(f, "\n    hash mask %08x at %d ",
1271                                 (unsigned int)htonl(sel->hmask), sel->hoff);
1272                 }
1273         }
1274
1275         if (tb[TCA_U32_POLICE]) {
1276                 fprintf(f, "\n");
1277                 tc_print_police(f, tb[TCA_U32_POLICE]);
1278         }
1279         if (tb[TCA_U32_INDEV]) {
1280                 struct rtattr *idev = tb[TCA_U32_INDEV];
1281                 fprintf(f, "\n  input dev %s\n", (char *) RTA_DATA(idev));
1282         }
1283         if (tb[TCA_U32_ACT]) {
1284                 tc_print_action(f, tb[TCA_U32_ACT]);
1285         }
1286
1287         return 0;
1288 }
1289
1290 struct filter_util u32_filter_util = {
1291         .id = "u32",
1292         .parse_fopt = u32_parse_opt,
1293         .print_fopt = u32_print_opt,
1294 };