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
explain(void)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
get_u32_handle(__u32 * handle,const char * str)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
sprint_u32_handle(__u32 handle,char * buf)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
pack_key(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)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
pack_key32(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)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
pack_key16(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)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
pack_key8(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)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
parse_at(int * argc_p,char *** argv_p,int * off,int * offmask)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
parse_u32(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)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
parse_u16(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)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
parse_u8(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)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
parse_ip_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)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
parse_ip6_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)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
parse_ip6_class(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)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 if (res = pack_key(sel, key, mask, off, offmask) < 0)
436 return -1;
437
438 *argc_p = argc;
439 *argv_p = argv;
440 return 0;
441 }
442
parse_ether_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)443 static int parse_ether_addr(int *argc_p, char ***argv_p,
444 struct tc_u32_sel *sel, int off)
445 {
446 int res = -1;
447 int argc = *argc_p;
448 char **argv = *argv_p;
449 __u8 addr[6];
450 int offmask = 0;
451 int i;
452
453 if (argc < 1)
454 return -1;
455
456 if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
457 addr + 0, addr + 1, addr + 2,
458 addr + 3, addr + 4, addr + 5) != 6) {
459 fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
460 *argv);
461 return -1;
462 }
463
464 argc--; argv++;
465 if (argc > 0 && strcmp(argv[0], "at") == 0) {
466 NEXT_ARG();
467 if (parse_at(&argc, &argv, &off, &offmask))
468 return -1;
469 }
470
471 for (i = 0; i < 6; i++) {
472 res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
473 if (res < 0)
474 return -1;
475 }
476
477 *argc_p = argc;
478 *argv_p = argv;
479 return res;
480 }
481
parse_ip(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)482 static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
483 {
484 int res = -1;
485 int argc = *argc_p;
486 char **argv = *argv_p;
487
488 if (argc < 2)
489 return -1;
490
491 if (strcmp(*argv, "src") == 0) {
492 NEXT_ARG();
493 res = parse_ip_addr(&argc, &argv, sel, 12);
494 } else if (strcmp(*argv, "dst") == 0) {
495 NEXT_ARG();
496 res = parse_ip_addr(&argc, &argv, sel, 16);
497 } else if (strcmp(*argv, "tos") == 0 ||
498 matches(*argv, "dsfield") == 0) {
499 NEXT_ARG();
500 res = parse_u8(&argc, &argv, sel, 1, 0);
501 } else if (strcmp(*argv, "ihl") == 0) {
502 NEXT_ARG();
503 res = parse_u8(&argc, &argv, sel, 0, 0);
504 } else if (strcmp(*argv, "protocol") == 0) {
505 NEXT_ARG();
506 res = parse_u8(&argc, &argv, sel, 9, 0);
507 } else if (matches(*argv, "precedence") == 0) {
508 NEXT_ARG();
509 res = parse_u8(&argc, &argv, sel, 1, 0);
510 } else if (strcmp(*argv, "nofrag") == 0) {
511 argc--; argv++;
512 res = pack_key16(sel, 0, 0x3FFF, 6, 0);
513 } else if (strcmp(*argv, "firstfrag") == 0) {
514 argc--; argv++;
515 res = pack_key16(sel, 0, 0x1FFF, 6, 0);
516 } else if (strcmp(*argv, "df") == 0) {
517 argc--; argv++;
518 res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
519 } else if (strcmp(*argv, "mf") == 0) {
520 argc--; argv++;
521 res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
522 } else if (strcmp(*argv, "dport") == 0) {
523 NEXT_ARG();
524 res = parse_u16(&argc, &argv, sel, 22, 0);
525 } else if (strcmp(*argv, "sport") == 0) {
526 NEXT_ARG();
527 res = parse_u16(&argc, &argv, sel, 20, 0);
528 } else if (strcmp(*argv, "icmp_type") == 0) {
529 NEXT_ARG();
530 res = parse_u8(&argc, &argv, sel, 20, 0);
531 } else if (strcmp(*argv, "icmp_code") == 0) {
532 NEXT_ARG();
533 res = parse_u8(&argc, &argv, sel, 20, 1);
534 } else
535 return -1;
536
537 *argc_p = argc;
538 *argv_p = argv;
539 return res;
540 }
541
parse_ip6(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)542 static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
543 {
544 int res = -1;
545 int argc = *argc_p;
546 char **argv = *argv_p;
547
548 if (argc < 2)
549 return -1;
550
551 if (strcmp(*argv, "src") == 0) {
552 NEXT_ARG();
553 res = parse_ip6_addr(&argc, &argv, sel, 8);
554 } else if (strcmp(*argv, "dst") == 0) {
555 NEXT_ARG();
556 res = parse_ip6_addr(&argc, &argv, sel, 24);
557 } else if (strcmp(*argv, "priority") == 0) {
558 NEXT_ARG();
559 res = parse_ip6_class(&argc, &argv, sel);
560 } else if (strcmp(*argv, "protocol") == 0) {
561 NEXT_ARG();
562 res = parse_u8(&argc, &argv, sel, 6, 0);
563 } else if (strcmp(*argv, "flowlabel") == 0) {
564 NEXT_ARG();
565 res = parse_u32(&argc, &argv, sel, 0, 0);
566 } else if (strcmp(*argv, "dport") == 0) {
567 NEXT_ARG();
568 res = parse_u16(&argc, &argv, sel, 42, 0);
569 } else if (strcmp(*argv, "sport") == 0) {
570 NEXT_ARG();
571 res = parse_u16(&argc, &argv, sel, 40, 0);
572 } else if (strcmp(*argv, "icmp_type") == 0) {
573 NEXT_ARG();
574 res = parse_u8(&argc, &argv, sel, 40, 0);
575 } else if (strcmp(*argv, "icmp_code") == 0) {
576 NEXT_ARG();
577 res = parse_u8(&argc, &argv, sel, 41, 1);
578 } else
579 return -1;
580
581 *argc_p = argc;
582 *argv_p = argv;
583 return res;
584 }
585
parse_ether(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)586 static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
587 {
588 int res = -1;
589 int argc = *argc_p;
590 char **argv = *argv_p;
591
592 if (argc < 2)
593 return -1;
594
595 if (strcmp(*argv, "src") == 0) {
596 NEXT_ARG();
597 res = parse_ether_addr(&argc, &argv, sel, -8);
598 } else if (strcmp(*argv, "dst") == 0) {
599 NEXT_ARG();
600 res = parse_ether_addr(&argc, &argv, sel, -14);
601 } else {
602 fprintf(stderr, "Unknown match: ether %s\n", *argv);
603 return -1;
604 }
605
606 *argc_p = argc;
607 *argv_p = argv;
608 return res;
609 }
610
611 #define parse_tcp parse_udp
parse_udp(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)612 static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
613 {
614 int res = -1;
615 int argc = *argc_p;
616 char **argv = *argv_p;
617
618 if (argc < 2)
619 return -1;
620
621 if (strcmp(*argv, "src") == 0) {
622 NEXT_ARG();
623 res = parse_u16(&argc, &argv, sel, 0, -1);
624 } else if (strcmp(*argv, "dst") == 0) {
625 NEXT_ARG();
626 res = parse_u16(&argc, &argv, sel, 2, -1);
627 } else
628 return -1;
629
630 *argc_p = argc;
631 *argv_p = argv;
632 return res;
633 }
634
635
parse_icmp(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)636 static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
637 {
638 int res = -1;
639 int argc = *argc_p;
640 char **argv = *argv_p;
641
642 if (argc < 2)
643 return -1;
644
645 if (strcmp(*argv, "type") == 0) {
646 NEXT_ARG();
647 res = parse_u8(&argc, &argv, sel, 0, -1);
648 } else if (strcmp(*argv, "code") == 0) {
649 NEXT_ARG();
650 res = parse_u8(&argc, &argv, sel, 1, -1);
651 } else
652 return -1;
653
654 *argc_p = argc;
655 *argv_p = argv;
656 return res;
657 }
658
parse_mark(int * argc_p,char *** argv_p,struct nlmsghdr * n)659 static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
660 {
661 int res = -1;
662 int argc = *argc_p;
663 char **argv = *argv_p;
664 struct tc_u32_mark mark;
665
666 if (argc <= 1)
667 return -1;
668
669 if (get_u32(&mark.val, *argv, 0)) {
670 fprintf(stderr, "Illegal \"mark\" value\n");
671 return -1;
672 }
673 NEXT_ARG();
674
675 if (get_u32(&mark.mask, *argv, 0)) {
676 fprintf(stderr, "Illegal \"mark\" mask\n");
677 return -1;
678 }
679 NEXT_ARG();
680
681 if ((mark.val & mark.mask) != mark.val) {
682 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
683 return -1;
684 }
685
686 addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
687 res = 0;
688
689 *argc_p = argc;
690 *argv_p = argv;
691 return res;
692 }
693
parse_selector(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,struct nlmsghdr * n)694 static int parse_selector(int *argc_p, char ***argv_p,
695 struct tc_u32_sel *sel, struct nlmsghdr *n)
696 {
697 int argc = *argc_p;
698 char **argv = *argv_p;
699 int res = -1;
700
701 if (argc <= 0)
702 return -1;
703
704 if (matches(*argv, "u32") == 0) {
705 NEXT_ARG();
706 res = parse_u32(&argc, &argv, sel, 0, 0);
707 } else if (matches(*argv, "u16") == 0) {
708 NEXT_ARG();
709 res = parse_u16(&argc, &argv, sel, 0, 0);
710 } else if (matches(*argv, "u8") == 0) {
711 NEXT_ARG();
712 res = parse_u8(&argc, &argv, sel, 0, 0);
713 } else if (matches(*argv, "ip") == 0) {
714 NEXT_ARG();
715 res = parse_ip(&argc, &argv, sel);
716 } else if (matches(*argv, "ip6") == 0) {
717 NEXT_ARG();
718 res = parse_ip6(&argc, &argv, sel);
719 } else if (matches(*argv, "udp") == 0) {
720 NEXT_ARG();
721 res = parse_udp(&argc, &argv, sel);
722 } else if (matches(*argv, "tcp") == 0) {
723 NEXT_ARG();
724 res = parse_tcp(&argc, &argv, sel);
725 } else if (matches(*argv, "icmp") == 0) {
726 NEXT_ARG();
727 res = parse_icmp(&argc, &argv, sel);
728 } else if (matches(*argv, "mark") == 0) {
729 NEXT_ARG();
730 res = parse_mark(&argc, &argv, n);
731 } else if (matches(*argv, "ether") == 0) {
732 NEXT_ARG();
733 res = parse_ether(&argc, &argv, sel);
734 } else
735 return -1;
736
737 *argc_p = argc;
738 *argv_p = argv;
739 return res;
740 }
741
parse_offset(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)742 static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
743 {
744 int argc = *argc_p;
745 char **argv = *argv_p;
746
747 while (argc > 0) {
748 if (matches(*argv, "plus") == 0) {
749 int off;
750 NEXT_ARG();
751 if (get_integer(&off, *argv, 0))
752 return -1;
753 sel->off = off;
754 sel->flags |= TC_U32_OFFSET;
755 } else if (matches(*argv, "at") == 0) {
756 int off;
757 NEXT_ARG();
758 if (get_integer(&off, *argv, 0))
759 return -1;
760 sel->offoff = off;
761 if (off%2) {
762 fprintf(stderr, "offset \"at\" must be even\n");
763 return -1;
764 }
765 sel->flags |= TC_U32_VAROFFSET;
766 } else if (matches(*argv, "mask") == 0) {
767 __u16 mask;
768 NEXT_ARG();
769 if (get_u16(&mask, *argv, 16))
770 return -1;
771 sel->offmask = htons(mask);
772 sel->flags |= TC_U32_VAROFFSET;
773 } else if (matches(*argv, "shift") == 0) {
774 int shift;
775 NEXT_ARG();
776 if (get_integer(&shift, *argv, 0))
777 return -1;
778 sel->offshift = shift;
779 sel->flags |= TC_U32_VAROFFSET;
780 } else if (matches(*argv, "eat") == 0) {
781 sel->flags |= TC_U32_EAT;
782 } else {
783 break;
784 }
785 argc--; argv++;
786 }
787
788 *argc_p = argc;
789 *argv_p = argv;
790 return 0;
791 }
792
parse_hashkey(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)793 static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
794 {
795 int argc = *argc_p;
796 char **argv = *argv_p;
797
798 while (argc > 0) {
799 if (matches(*argv, "mask") == 0) {
800 __u32 mask;
801 NEXT_ARG();
802 if (get_u32(&mask, *argv, 16))
803 return -1;
804 sel->hmask = htonl(mask);
805 } else if (matches(*argv, "at") == 0) {
806 int num;
807 NEXT_ARG();
808 if (get_integer(&num, *argv, 0))
809 return -1;
810 if (num%4)
811 return -1;
812 sel->hoff = num;
813 } else {
814 break;
815 }
816 argc--; argv++;
817 }
818
819 *argc_p = argc;
820 *argv_p = argv;
821 return 0;
822 }
823
print_ipv4(FILE * f,const struct tc_u32_key * key)824 static void print_ipv4(FILE *f, const struct tc_u32_key *key)
825 {
826 char abuf[256];
827
828 switch (key->off) {
829 case 0:
830 switch (ntohl(key->mask)) {
831 case 0x0f000000:
832 fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24);
833 return;
834 case 0x00ff0000:
835 fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16);
836 return;
837 }
838 break;
839 case 8:
840 if (ntohl(key->mask) == 0x00ff0000) {
841 fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16);
842 return;
843 }
844 break;
845 case 12:
846 case 16: {
847 int bits = mask2bits(key->mask);
848 if (bits >= 0) {
849 fprintf(f, "\n %s %s/%d",
850 key->off == 12 ? "match IP src" : "match IP dst",
851 inet_ntop(AF_INET, &key->val,
852 abuf, sizeof(abuf)),
853 bits);
854 return;
855 }
856 }
857 break;
858
859 case 20:
860 switch (ntohl(key->mask)) {
861 case 0x0000ffff:
862 fprintf(f, "\n match sport %u",
863 ntohl(key->val) & 0xffff);
864 return;
865 case 0xffff0000:
866 fprintf(f, "\n match dport %u",
867 ntohl(key->val) >> 16);
868 return;
869 case 0xffffffff:
870 fprintf(f, "\n match sport %u, match dport %u",
871 ntohl(key->val) & 0xffff,
872 ntohl(key->val) >> 16);
873
874 return;
875 }
876 /* XXX: Default print_raw */
877 }
878 }
879
print_ipv6(FILE * f,const struct tc_u32_key * key)880 static void print_ipv6(FILE *f, const struct tc_u32_key *key)
881 {
882 char abuf[256];
883
884 switch (key->off) {
885 case 0:
886 switch (ntohl(key->mask)) {
887 case 0x0f000000:
888 fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24);
889 return;
890 case 0x00ff0000:
891 fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16);
892 return;
893 }
894 break;
895 case 8:
896 if (ntohl(key->mask) == 0x00ff0000) {
897 fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16);
898 return;
899 }
900 break;
901 case 12:
902 case 16: {
903 int bits = mask2bits(key->mask);
904 if (bits >= 0) {
905 fprintf(f, "\n %s %s/%d",
906 key->off == 12 ? "match IP src" : "match IP dst",
907 inet_ntop(AF_INET, &key->val,
908 abuf, sizeof(abuf)),
909 bits);
910 return;
911 }
912 }
913 break;
914
915 case 20:
916 switch (ntohl(key->mask)) {
917 case 0x0000ffff:
918 fprintf(f, "\n match sport %u",
919 ntohl(key->val) & 0xffff);
920 return;
921 case 0xffff0000:
922 fprintf(f, "\n match dport %u",
923 ntohl(key->val) >> 16);
924 return;
925 case 0xffffffff:
926 fprintf(f, "\n match sport %u, match dport %u",
927 ntohl(key->val) & 0xffff,
928 ntohl(key->val) >> 16);
929
930 return;
931 }
932 /* XXX: Default print_raw */
933 }
934 }
935
print_raw(FILE * f,const struct tc_u32_key * key)936 static void print_raw(FILE *f, const struct tc_u32_key *key)
937 {
938 fprintf(f, "\n match %08x/%08x at %s%d",
939 (unsigned int)ntohl(key->val),
940 (unsigned int)ntohl(key->mask),
941 key->offmask ? "nexthdr+" : "",
942 key->off);
943 }
944
945 static const struct {
946 __u16 proto;
947 __u16 pad;
948 void (*pprinter)(FILE *f, const struct tc_u32_key *key);
949 } u32_pprinters[] = {
950 {0, 0, print_raw},
951 {ETH_P_IP, 0, print_ipv4},
952 {ETH_P_IPV6, 0, print_ipv6},
953 };
954
show_keys(FILE * f,const struct tc_u32_key * key)955 static void show_keys(FILE *f, const struct tc_u32_key *key)
956 {
957 int i = 0;
958
959 if (!show_pretty)
960 goto show_k;
961
962 for (i = 0; i < sizeof(u32_pprinters) / sizeof(u32_pprinters[0]); i++) {
963 if (u32_pprinters[i].proto == ntohs(f_proto)) {
964 show_k:
965 u32_pprinters[i].pprinter(f, key);
966 return;
967 }
968 }
969
970 i = 0;
971 goto show_k;
972 }
973
u32_parse_opt(struct filter_util * qu,char * handle,int argc,char ** argv,struct nlmsghdr * n)974 static int u32_parse_opt(struct filter_util *qu, char *handle,
975 int argc, char **argv, struct nlmsghdr *n)
976 {
977 struct {
978 struct tc_u32_sel sel;
979 struct tc_u32_key keys[128];
980 } sel;
981 struct tcmsg *t = NLMSG_DATA(n);
982 struct rtattr *tail;
983 int sel_ok = 0, terminal_ok = 0;
984 int sample_ok = 0;
985 __u32 htid = 0;
986 __u32 order = 0;
987
988 memset(&sel, 0, sizeof(sel));
989
990 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
991 fprintf(stderr, "Illegal filter ID\n");
992 return -1;
993 }
994
995 if (argc == 0)
996 return 0;
997
998 tail = NLMSG_TAIL(n);
999 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
1000
1001 while (argc > 0) {
1002 if (matches(*argv, "match") == 0) {
1003 NEXT_ARG();
1004 if (parse_selector(&argc, &argv, &sel.sel, n)) {
1005 fprintf(stderr, "Illegal \"match\"\n");
1006 return -1;
1007 }
1008 sel_ok++;
1009 continue;
1010 } else if (matches(*argv, "offset") == 0) {
1011 NEXT_ARG();
1012 if (parse_offset(&argc, &argv, &sel.sel)) {
1013 fprintf(stderr, "Illegal \"offset\"\n");
1014 return -1;
1015 }
1016 continue;
1017 } else if (matches(*argv, "hashkey") == 0) {
1018 NEXT_ARG();
1019 if (parse_hashkey(&argc, &argv, &sel.sel)) {
1020 fprintf(stderr, "Illegal \"hashkey\"\n");
1021 return -1;
1022 }
1023 continue;
1024 } else if (matches(*argv, "classid") == 0 ||
1025 strcmp(*argv, "flowid") == 0) {
1026 unsigned handle;
1027 NEXT_ARG();
1028 if (get_tc_classid(&handle, *argv)) {
1029 fprintf(stderr, "Illegal \"classid\"\n");
1030 return -1;
1031 }
1032 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4);
1033 sel.sel.flags |= TC_U32_TERMINAL;
1034 } else if (matches(*argv, "divisor") == 0) {
1035 unsigned divisor;
1036 NEXT_ARG();
1037 if (get_unsigned(&divisor, *argv, 0) ||
1038 divisor == 0 ||
1039 divisor > 0x100 || ((divisor - 1) & divisor)) {
1040 fprintf(stderr, "Illegal \"divisor\"\n");
1041 return -1;
1042 }
1043 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
1044 } else if (matches(*argv, "order") == 0) {
1045 NEXT_ARG();
1046 if (get_u32(&order, *argv, 0)) {
1047 fprintf(stderr, "Illegal \"order\"\n");
1048 return -1;
1049 }
1050 } else if (strcmp(*argv, "link") == 0) {
1051 unsigned handle;
1052 NEXT_ARG();
1053 if (get_u32_handle(&handle, *argv)) {
1054 fprintf(stderr, "Illegal \"link\"\n");
1055 return -1;
1056 }
1057 if (handle && TC_U32_NODE(handle)) {
1058 fprintf(stderr, "\"link\" must be a hash table.\n");
1059 return -1;
1060 }
1061 addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4);
1062 } else if (strcmp(*argv, "ht") == 0) {
1063 unsigned handle;
1064 NEXT_ARG();
1065 if (get_u32_handle(&handle, *argv)) {
1066 fprintf(stderr, "Illegal \"ht\"\n");
1067 return -1;
1068 }
1069 if (handle && TC_U32_NODE(handle)) {
1070 fprintf(stderr, "\"ht\" must be a hash table.\n");
1071 return -1;
1072 }
1073 if (sample_ok)
1074 htid = (htid&0xFF000)|(handle&0xFFF00000);
1075 else
1076 htid = (handle&0xFFFFF000);
1077 } else if (strcmp(*argv, "sample") == 0) {
1078 __u32 hash;
1079 unsigned divisor = 0x100;
1080
1081 struct {
1082 struct tc_u32_sel sel;
1083 struct tc_u32_key keys[4];
1084 } sel2;
1085 memset(&sel2, 0, sizeof(sel2));
1086 NEXT_ARG();
1087 if (parse_selector(&argc, &argv, &sel2.sel, n)) {
1088 fprintf(stderr, "Illegal \"sample\"\n");
1089 return -1;
1090 }
1091 if (sel2.sel.nkeys != 1) {
1092 fprintf(stderr, "\"sample\" must contain"
1093 " exactly ONE key.\n");
1094 return -1;
1095 }
1096 if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1097 NEXT_ARG();
1098 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
1099 divisor > 0x100 || ((divisor - 1) & divisor)) {
1100 fprintf(stderr, "Illegal sample \"divisor\"\n");
1101 return -1;
1102 }
1103 NEXT_ARG();
1104 }
1105 hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask;
1106 hash ^= hash>>16;
1107 hash ^= hash>>8;
1108 htid = ((hash%divisor)<<12)|(htid&0xFFF00000);
1109 sample_ok = 1;
1110 continue;
1111 } else if (strcmp(*argv, "indev") == 0) {
1112 char ind[IFNAMSIZ + 1];
1113 memset(ind, 0, sizeof (ind));
1114 argc--;
1115 argv++;
1116 if (argc < 1) {
1117 fprintf(stderr, "Illegal indev\n");
1118 return -1;
1119 }
1120 strncpy(ind, *argv, sizeof (ind) - 1);
1121 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1);
1122
1123 } else if (matches(*argv, "action") == 0) {
1124 NEXT_ARG();
1125 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1126 fprintf(stderr, "Illegal \"action\"\n");
1127 return -1;
1128 }
1129 terminal_ok++;
1130 continue;
1131
1132 } else if (matches(*argv, "police") == 0) {
1133 NEXT_ARG();
1134 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1135 fprintf(stderr, "Illegal \"police\"\n");
1136 return -1;
1137 }
1138 terminal_ok++;
1139 continue;
1140 } else if (strcmp(*argv, "help") == 0) {
1141 explain();
1142 return -1;
1143 } else {
1144 fprintf(stderr, "What is \"%s\"?\n", *argv);
1145 explain();
1146 return -1;
1147 }
1148 argc--; argv++;
1149 }
1150
1151 /* We dont necessarily need class/flowids */
1152 if (terminal_ok)
1153 sel.sel.flags |= TC_U32_TERMINAL;
1154
1155 if (order) {
1156 if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
1157 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1158 return -1;
1159 }
1160 t->tcm_handle |= order;
1161 }
1162
1163 if (htid)
1164 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
1165 if (sel_ok)
1166 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
1167 sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
1168 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
1169 return 0;
1170 }
1171
u32_print_opt(struct filter_util * qu,FILE * f,struct rtattr * opt,__u32 handle)1172 static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1173 __u32 handle)
1174 {
1175 struct rtattr *tb[TCA_U32_MAX+1];
1176 struct tc_u32_sel *sel = NULL;
1177 struct tc_u32_pcnt *pf = NULL;
1178
1179 if (opt == NULL)
1180 return 0;
1181
1182 parse_rtattr_nested(tb, TCA_U32_MAX, opt);
1183
1184 if (handle) {
1185 SPRINT_BUF(b1);
1186 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1187 }
1188 if (TC_U32_NODE(handle)) {
1189 fprintf(f, "order %d ", TC_U32_NODE(handle));
1190 }
1191
1192 if (tb[TCA_U32_SEL]) {
1193 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
1194 return -1;
1195
1196 sel = RTA_DATA(tb[TCA_U32_SEL]);
1197 }
1198
1199 if (tb[TCA_U32_DIVISOR]) {
1200 fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR]));
1201 } else if (tb[TCA_U32_HASH]) {
1202 __u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]);
1203 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1204 TC_U32_HASH(htid));
1205 } else {
1206 fprintf(f, "??? ");
1207 }
1208 if (tb[TCA_U32_CLASSID]) {
1209 SPRINT_BUF(b1);
1210 fprintf(f, "%sflowid %s ",
1211 !sel || !(sel->flags&TC_U32_TERMINAL) ? "*" : "",
1212 sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_U32_CLASSID]), b1));
1213 } else if (sel && sel->flags&TC_U32_TERMINAL) {
1214 fprintf(f, "terminal flowid ??? ");
1215 }
1216 if (tb[TCA_U32_LINK]) {
1217 SPRINT_BUF(b1);
1218 fprintf(f, "link %s ",
1219 sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
1220 }
1221
1222 if (tb[TCA_U32_PCNT]) {
1223 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) {
1224 fprintf(f, "Broken perf counters \n");
1225 return -1;
1226 }
1227 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1228 }
1229
1230 if (sel && show_stats && NULL != pf)
1231 fprintf(f, " (rule hit %llu success %llu)",
1232 (unsigned long long) pf->rcnt,
1233 (unsigned long long) pf->rhit);
1234
1235 if (tb[TCA_U32_MARK]) {
1236 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1237 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1238 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1239 } else {
1240 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)",
1241 mark->val, mark->mask, mark->success);
1242 }
1243 }
1244
1245 if (sel) {
1246 if (sel->nkeys) {
1247 int i;
1248 for (i=0; i<sel->nkeys; i++) {
1249 show_keys(f, sel->keys + i);
1250 if (show_stats && NULL != pf)
1251 fprintf(f, " (success %llu ) ",
1252 (unsigned long long) pf->kcnts[i]);
1253 }
1254 }
1255
1256 if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) {
1257 fprintf(f, "\n offset ");
1258 if (sel->flags&TC_U32_VAROFFSET)
1259 fprintf(f, "%04x>>%d at %d ",
1260 ntohs(sel->offmask),
1261 sel->offshift, sel->offoff);
1262 if (sel->off)
1263 fprintf(f, "plus %d ", sel->off);
1264 }
1265 if (sel->flags&TC_U32_EAT)
1266 fprintf(f, " eat ");
1267
1268 if (sel->hmask) {
1269 fprintf(f, "\n hash mask %08x at %d ",
1270 (unsigned int)htonl(sel->hmask), sel->hoff);
1271 }
1272 }
1273
1274 if (tb[TCA_U32_POLICE]) {
1275 fprintf(f, "\n");
1276 tc_print_police(f, tb[TCA_U32_POLICE]);
1277 }
1278 if (tb[TCA_U32_INDEV]) {
1279 struct rtattr *idev = tb[TCA_U32_INDEV];
1280 fprintf(f, "\n input dev %s\n", (char *) RTA_DATA(idev));
1281 }
1282 if (tb[TCA_U32_ACT]) {
1283 tc_print_action(f, tb[TCA_U32_ACT]);
1284 }
1285
1286 return 0;
1287 }
1288
1289 struct filter_util u32_filter_util = {
1290 .id = "u32",
1291 .parse_fopt = u32_parse_opt,
1292 .print_fopt = u32_print_opt,
1293 };
1294