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 25#include "utils.h" 26#include "tc_util.h" 27 28static void explain(void) 29{ 30 fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"); 31 fprintf(stderr, " [ police POLICE_SPEC ] [ offset OFFSET_SPEC ]\n"); 32 fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"); 33 fprintf(stderr, " [ sample SAMPLE ]\n"); 34 fprintf(stderr, "or u32 divisor DIVISOR\n"); 35 fprintf(stderr, "\n"); 36 fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); 37 fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS\n"); 38 fprintf(stderr, " FILTERID := X:Y:Z\n"); 39} 40 41#define usage() return(-1) 42 43int get_u32_handle(__u32 *handle, char *str) 44{ 45 __u32 htid=0, hash=0, nodeid=0; 46 char *tmp = strchr(str, ':'); 47 48 if (tmp == NULL) { 49 if (memcmp("0x", str, 2) == 0) 50 return get_u32(handle, str, 16); 51 return -1; 52 } 53 htid = strtoul(str, &tmp, 16); 54 if (tmp == str && *str != ':' && *str != 0) 55 return -1; 56 if (htid>=0x1000) 57 return -1; 58 if (*tmp) { 59 str = tmp+1; 60 hash = strtoul(str, &tmp, 16); 61 if (tmp == str && *str != ':' && *str != 0) 62 return -1; 63 if (hash>=0x100) 64 return -1; 65 if (*tmp) { 66 str = tmp+1; 67 nodeid = strtoul(str, &tmp, 16); 68 if (tmp == str && *str != 0) 69 return -1; 70 if (nodeid>=0x1000) 71 return -1; 72 } 73 } 74 *handle = (htid<<20)|(hash<<12)|nodeid; 75 return 0; 76} 77 78char * sprint_u32_handle(__u32 handle, char *buf) 79{ 80 int bsize = SPRINT_BSIZE-1; 81 __u32 htid = TC_U32_HTID(handle); 82 __u32 hash = TC_U32_HASH(handle); 83 __u32 nodeid = TC_U32_NODE(handle); 84 char *b = buf; 85 86 if (handle == 0) { 87 snprintf(b, bsize, "none"); 88 return b; 89 } 90 if (htid) { 91 int l = snprintf(b, bsize, "%x:", htid>>20); 92 bsize -= l; 93 b += l; 94 } 95 if (nodeid|hash) { 96 if (hash) { 97 int l = snprintf(b, bsize, "%x", hash); 98 bsize -= l; 99 b += l; 100 } 101 if (nodeid) { 102 int l = snprintf(b, bsize, ":%x", nodeid); 103 bsize -= l; 104 b += l; 105 } 106 } 107 if (show_raw) 108 snprintf(b, bsize, "[%08x] ", handle); 109 return buf; 110} 111 112static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask) 113{ 114 int i; 115 int hwm = sel->nkeys; 116 117 key &= mask; 118 119 for (i=0; i<hwm; i++) { 120 if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) { 121 __u32 intersect = mask&sel->keys[i].mask; 122 123 if ((key^sel->keys[i].val) & intersect) 124 return -1; 125 sel->keys[i].val |= key; 126 sel->keys[i].mask |= mask; 127 return 0; 128 } 129 } 130 131 if (hwm >= 128) 132 return -1; 133 if (off % 4) 134 return -1; 135 sel->keys[hwm].val = key; 136 sel->keys[hwm].mask = mask; 137 sel->keys[hwm].off = off; 138 sel->keys[hwm].offmask = offmask; 139 sel->nkeys++; 140 return 0; 141} 142 143static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask) 144{ 145 key = htonl(key); 146 mask = htonl(mask); 147 return pack_key(sel, key, mask, off, offmask); 148} 149 150static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask) 151{ 152 if (key > 0xFFFF || mask > 0xFFFF) 153 return -1; 154 155 if ((off & 3) == 0) { 156 key <<= 16; 157 mask <<= 16; 158 } 159 off &= ~3; 160 key = htonl(key); 161 mask = htonl(mask); 162 163 return pack_key(sel, key, mask, off, offmask); 164} 165 166static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask) 167{ 168 if (key > 0xFF || mask > 0xFF) 169 return -1; 170 171 if ((off & 3) == 0) { 172 key <<= 24; 173 mask <<= 24; 174 } else if ((off & 3) == 1) { 175 key <<= 16; 176 mask <<= 16; 177 } else if ((off & 3) == 2) { 178 key <<= 8; 179 mask <<= 8; 180 } 181 off &= ~3; 182 key = htonl(key); 183 mask = htonl(mask); 184 185 return pack_key(sel, key, mask, off, offmask); 186} 187 188 189int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask) 190{ 191 int argc = *argc_p; 192 char **argv = *argv_p; 193 char *p = *argv; 194 195 if (argc <= 0) 196 return -1; 197 198 if (strlen(p) > strlen("nexthdr+") && 199 memcmp(p, "nexthdr+", strlen("nexthdr+")) == 0) { 200 *offmask = -1; 201 p += strlen("nexthdr+"); 202 } else if (matches(*argv, "nexthdr+") == 0) { 203 NEXT_ARG(); 204 *offmask = -1; 205 p = *argv; 206 } 207 208 if (get_integer(off, p, 0)) 209 return -1; 210 argc--; argv++; 211 212 *argc_p = argc; 213 *argv_p = argv; 214 return 0; 215} 216 217 218static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask) 219{ 220 int res = -1; 221 int argc = *argc_p; 222 char **argv = *argv_p; 223 __u32 key; 224 __u32 mask; 225 226 if (argc < 2) 227 return -1; 228 229 if (get_u32(&key, *argv, 0)) 230 return -1; 231 argc--; argv++; 232 233 if (get_u32(&mask, *argv, 16)) 234 return -1; 235 argc--; argv++; 236 237 if (argc > 0 && strcmp(argv[0], "at") == 0) { 238 NEXT_ARG(); 239 if (parse_at(&argc, &argv, &off, &offmask)) 240 return -1; 241 } 242 243 res = pack_key32(sel, key, mask, off, offmask); 244 *argc_p = argc; 245 *argv_p = argv; 246 return res; 247} 248 249static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask) 250{ 251 int res = -1; 252 int argc = *argc_p; 253 char **argv = *argv_p; 254 __u32 key; 255 __u32 mask; 256 257 if (argc < 2) 258 return -1; 259 260 if (get_u32(&key, *argv, 0)) 261 return -1; 262 argc--; argv++; 263 264 if (get_u32(&mask, *argv, 16)) 265 return -1; 266 argc--; argv++; 267 268 if (argc > 0 && strcmp(argv[0], "at") == 0) { 269 NEXT_ARG(); 270 if (parse_at(&argc, &argv, &off, &offmask)) 271 return -1; 272 } 273 res = pack_key16(sel, key, mask, off, offmask); 274 *argc_p = argc; 275 *argv_p = argv; 276 return res; 277} 278 279static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask) 280{ 281 int res = -1; 282 int argc = *argc_p; 283 char **argv = *argv_p; 284 __u32 key; 285 __u32 mask; 286 287 if (argc < 2) 288 return -1; 289 290 if (get_u32(&key, *argv, 0)) 291 return -1; 292 argc--; argv++; 293 294 if (get_u32(&mask, *argv, 16)) 295 return -1; 296 argc--; argv++; 297 298 if (key > 0xFF || mask > 0xFF) 299 return -1; 300 301 if (argc > 0 && strcmp(argv[0], "at") == 0) { 302 NEXT_ARG(); 303 if (parse_at(&argc, &argv, &off, &offmask)) 304 return -1; 305 } 306 307 res = pack_key8(sel, key, mask, off, offmask); 308 *argc_p = argc; 309 *argv_p = argv; 310 return res; 311} 312 313static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off) 314{ 315 int res = -1; 316 int argc = *argc_p; 317 char **argv = *argv_p; 318 inet_prefix addr; 319 __u32 mask; 320 int offmask = 0; 321 322 if (argc < 1) 323 return -1; 324 325 if (get_prefix_1(&addr, *argv, AF_INET)) 326 return -1; 327 argc--; argv++; 328 329 if (argc > 0 && strcmp(argv[0], "at") == 0) { 330 NEXT_ARG(); 331 if (parse_at(&argc, &argv, &off, &offmask)) 332 return -1; 333 } 334 335 mask = 0; 336 if (addr.bitlen) 337 mask = htonl(0xFFFFFFFF<<(32-addr.bitlen)); 338 if (pack_key(sel, addr.data[0], mask, off, offmask) < 0) 339 return -1; 340 res = 0; 341 342 *argc_p = argc; 343 *argv_p = argv; 344 return res; 345} 346 347static int parse_ip6_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off) 348{ 349 int res = -1; 350 int argc = *argc_p; 351 char **argv = *argv_p; 352 int plen = 128; 353 int i; 354 inet_prefix addr; 355 int offmask = 0; 356 357 if (argc < 1) 358 return -1; 359 360 if (get_prefix_1(&addr, *argv, AF_INET6)) 361 return -1; 362 argc--; argv++; 363 364 if (argc > 0 && strcmp(argv[0], "at") == 0) { 365 NEXT_ARG(); 366 if (parse_at(&argc, &argv, &off, &offmask)) 367 return -1; 368 } 369 370 plen = addr.bitlen; 371 for (i=0; i<plen; i+=32) { 372// if (((i+31)&~0x1F)<=plen) { 373 if (((i+31))<=plen) { 374 if ((res = pack_key(sel, addr.data[i/32], 0xFFFFFFFF, off+4*(i/32), offmask)) < 0) 375 return -1; 376 } else if (i<plen) { 377 __u32 mask = htonl(0xFFFFFFFF<<(32-(plen-i))); 378 if ((res = pack_key(sel, addr.data[i/32], mask, off+4*(i/32), offmask)) < 0) 379 return -1; 380 } 381 } 382 res = 0; 383 384 *argc_p = argc; 385 *argv_p = argv; 386 return res; 387} 388 389static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) 390{ 391 int res = -1; 392 int argc = *argc_p; 393 char **argv = *argv_p; 394 395 if (argc < 2) 396 return -1; 397 398 if (strcmp(*argv, "src") == 0) { 399 NEXT_ARG(); 400 res = parse_ip_addr(&argc, &argv, sel, 12); 401 goto done; 402 } 403 if (strcmp(*argv, "dst") == 0) { 404 NEXT_ARG(); 405 res = parse_ip_addr(&argc, &argv, sel, 16); 406 goto done; 407 } 408 if (strcmp(*argv, "tos") == 0 || 409 matches(*argv, "dsfield") == 0) { 410 NEXT_ARG(); 411 res = parse_u8(&argc, &argv, sel, 1, 0); 412 goto done; 413 } 414 if (strcmp(*argv, "ihl") == 0) { 415 NEXT_ARG(); 416 res = parse_u8(&argc, &argv, sel, 0, 0); 417 goto done; 418 } 419 if (strcmp(*argv, "protocol") == 0) { 420 NEXT_ARG(); 421 res = parse_u8(&argc, &argv, sel, 9, 0); 422 goto done; 423 } 424 if (matches(*argv, "precedence") == 0) { 425 NEXT_ARG(); 426 res = parse_u8(&argc, &argv, sel, 1, 0); 427 goto done; 428 } 429 if (strcmp(*argv, "nofrag") == 0) { 430 argc--; argv++; 431 res = pack_key16(sel, 0, 0x3FFF, 6, 0); 432 goto done; 433 } 434 if (strcmp(*argv, "firstfrag") == 0) { 435 argc--; argv++; 436 res = pack_key16(sel, 0, 0x1FFF, 6, 0); 437 goto done; 438 } 439 if (strcmp(*argv, "df") == 0) { 440 argc--; argv++; 441 res = pack_key16(sel, 0x4000, 0x4000, 6, 0); 442 goto done; 443 } 444 if (strcmp(*argv, "mf") == 0) { 445 argc--; argv++; 446 res = pack_key16(sel, 0x2000, 0x2000, 6, 0); 447 goto done; 448 } 449 if (strcmp(*argv, "dport") == 0) { 450 NEXT_ARG(); 451 res = parse_u16(&argc, &argv, sel, 22, 0); 452 goto done; 453 } 454 if (strcmp(*argv, "sport") == 0) { 455 NEXT_ARG(); 456 res = parse_u16(&argc, &argv, sel, 20, 0); 457 goto done; 458 } 459 if (strcmp(*argv, "icmp_type") == 0) { 460 NEXT_ARG(); 461 res = parse_u8(&argc, &argv, sel, 20, 0); 462 goto done; 463 } 464 if (strcmp(*argv, "icmp_code") == 0) { 465 NEXT_ARG(); 466 res = parse_u8(&argc, &argv, sel, 20, 1); 467 goto done; 468 } 469 return -1; 470 471done: 472 *argc_p = argc; 473 *argv_p = argv; 474 return res; 475} 476 477static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) 478{ 479 int res = -1; 480 int argc = *argc_p; 481 char **argv = *argv_p; 482 483 if (argc < 2) 484 return -1; 485 486 if (strcmp(*argv, "src") == 0) { 487 NEXT_ARG(); 488 res = parse_ip6_addr(&argc, &argv, sel, 8); 489 goto done; 490 } 491 if (strcmp(*argv, "dst") == 0) { 492 NEXT_ARG(); 493 res = parse_ip6_addr(&argc, &argv, sel, 24); 494 goto done; 495 } 496 if (strcmp(*argv, "priority") == 0) { 497 NEXT_ARG(); 498 res = parse_u8(&argc, &argv, sel, 0, 0); 499 goto done; 500 } 501 if (strcmp(*argv, "protocol") == 0) { 502 NEXT_ARG(); 503 res = parse_u8(&argc, &argv, sel, 6, 0); 504 goto done; 505 } 506 if (strcmp(*argv, "flowlabel") == 0) { 507 NEXT_ARG(); 508 res = parse_u32(&argc, &argv, sel, 0, 0); 509 goto done; 510 } 511 if (strcmp(*argv, "dport") == 0) { 512 NEXT_ARG(); 513 res = parse_u16(&argc, &argv, sel, 42, 0); 514 goto done; 515 } 516 if (strcmp(*argv, "sport") == 0) { 517 NEXT_ARG(); 518 res = parse_u16(&argc, &argv, sel, 40, 0); 519 goto done; 520 } 521 if (strcmp(*argv, "icmp_type") == 0) { 522 NEXT_ARG(); 523 res = parse_u8(&argc, &argv, sel, 40, 0); 524 goto done; 525 } 526 if (strcmp(*argv, "icmp_code") == 0) { 527 NEXT_ARG(); 528 res = parse_u8(&argc, &argv, sel, 41, 1); 529 goto done; 530 } 531 return -1; 532 533done: 534 *argc_p = argc; 535 *argv_p = argv; 536 return res; 537} 538 539#define parse_tcp parse_udp 540static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) 541{ 542 int res = -1; 543 int argc = *argc_p; 544 char **argv = *argv_p; 545 546 if (argc < 2) 547 return -1; 548 549 if (strcmp(*argv, "src") == 0) { 550 NEXT_ARG(); 551 res = parse_u16(&argc, &argv, sel, 0, -1); 552 goto done; 553 } 554 if (strcmp(*argv, "dst") == 0) { 555 NEXT_ARG(); 556 res = parse_u16(&argc, &argv, sel, 2, -1); 557 goto done; 558 } 559 return -1; 560 561done: 562 *argc_p = argc; 563 *argv_p = argv; 564 return res; 565} 566 567static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) 568{ 569 int res = -1; 570 int argc = *argc_p; 571 char **argv = *argv_p; 572 573 if (argc < 2) 574 return -1; 575 576 if (strcmp(*argv, "type") == 0) { 577 NEXT_ARG(); 578 res = parse_u8(&argc, &argv, sel, 0, -1); 579 goto done; 580 } 581 if (strcmp(*argv, "code") == 0) { 582 NEXT_ARG(); 583 res = parse_u8(&argc, &argv, sel, 1, -1); 584 goto done; 585 } 586 return -1; 587 588done: 589 *argc_p = argc; 590 *argv_p = argv; 591 return res; 592} 593 594static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n) 595{ 596 int res = -1; 597 int argc = *argc_p; 598 char **argv = *argv_p; 599 struct tc_u32_mark mark; 600 601 if (argc <= 1) 602 return -1; 603 604 if (get_u32(&mark.val, *argv, 0)) { 605 fprintf(stderr, "Illegal \"mark\" value\n"); 606 return -1; 607 } 608 NEXT_ARG(); 609 610 if (get_u32(&mark.mask, *argv, 0)) { 611 fprintf(stderr, "Illegal \"mark\" mask\n"); 612 return -1; 613 } 614 NEXT_ARG(); 615 616 if ((mark.val & mark.mask) != mark.val) { 617 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n"); 618 return -1; 619 } 620 621 addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark)); 622 res = 0; 623 624 *argc_p = argc; 625 *argv_p = argv; 626 return res; 627} 628 629static int parse_selector(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, struct nlmsghdr *n) 630{ 631 int argc = *argc_p; 632 char **argv = *argv_p; 633 int res = -1; 634 635 if (argc <= 0) 636 return -1; 637 638 if (matches(*argv, "u32") == 0) { 639 NEXT_ARG(); 640 res = parse_u32(&argc, &argv, sel, 0, 0); 641 goto done; 642 } 643 if (matches(*argv, "u16") == 0) { 644 NEXT_ARG(); 645 res = parse_u16(&argc, &argv, sel, 0, 0); 646 goto done; 647 } 648 if (matches(*argv, "u8") == 0) { 649 NEXT_ARG(); 650 res = parse_u8(&argc, &argv, sel, 0, 0); 651 goto done; 652 } 653 if (matches(*argv, "ip") == 0) { 654 NEXT_ARG(); 655 res = parse_ip(&argc, &argv, sel); 656 goto done; 657 } 658 if (matches(*argv, "ip6") == 0) { 659 NEXT_ARG(); 660 res = parse_ip6(&argc, &argv, sel); 661 goto done; 662 } 663 if (matches(*argv, "udp") == 0) { 664 NEXT_ARG(); 665 res = parse_udp(&argc, &argv, sel); 666 goto done; 667 } 668 if (matches(*argv, "tcp") == 0) { 669 NEXT_ARG(); 670 res = parse_tcp(&argc, &argv, sel); 671 goto done; 672 } 673 if (matches(*argv, "icmp") == 0) { 674 NEXT_ARG(); 675 res = parse_icmp(&argc, &argv, sel); 676 goto done; 677 } 678 if (matches(*argv, "mark") == 0) { 679 NEXT_ARG(); 680 res = parse_mark(&argc, &argv, n); 681 goto done; 682 } 683 684 return -1; 685 686done: 687 *argc_p = argc; 688 *argv_p = argv; 689 return res; 690} 691 692static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) 693{ 694 int argc = *argc_p; 695 char **argv = *argv_p; 696 697 while (argc > 0) { 698 if (matches(*argv, "plus") == 0) { 699 int off; 700 NEXT_ARG(); 701 if (get_integer(&off, *argv, 0)) 702 return -1; 703 sel->off = off; 704 sel->flags |= TC_U32_OFFSET; 705 } else if (matches(*argv, "at") == 0) { 706 int off; 707 NEXT_ARG(); 708 if (get_integer(&off, *argv, 0)) 709 return -1; 710 sel->offoff = off; 711 if (off%2) { 712 fprintf(stderr, "offset \"at\" must be even\n"); 713 return -1; 714 } 715 sel->flags |= TC_U32_VAROFFSET; 716 } else if (matches(*argv, "mask") == 0) { 717 __u16 mask; 718 NEXT_ARG(); 719 if (get_u16(&mask, *argv, 16)) 720 return -1; 721 sel->offmask = htons(mask); 722 sel->flags |= TC_U32_VAROFFSET; 723 } else if (matches(*argv, "shift") == 0) { 724 int shift; 725 NEXT_ARG(); 726 if (get_integer(&shift, *argv, 0)) 727 return -1; 728 sel->offshift = shift; 729 sel->flags |= TC_U32_VAROFFSET; 730 } else if (matches(*argv, "eat") == 0) { 731 sel->flags |= TC_U32_EAT; 732 } else { 733 break; 734 } 735 argc--; argv++; 736 } 737 738 *argc_p = argc; 739 *argv_p = argv; 740 return 0; 741} 742 743static int parse_hashkey(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, "mask") == 0) { 750 __u32 mask; 751 NEXT_ARG(); 752 if (get_u32(&mask, *argv, 16)) 753 return -1; 754 sel->hmask = htonl(mask); 755 } else if (matches(*argv, "at") == 0) { 756 int num; 757 NEXT_ARG(); 758 if (get_integer(&num, *argv, 0)) 759 return -1; 760 if (num%4) 761 return -1; 762 sel->hoff = num; 763 } else { 764 break; 765 } 766 argc--; argv++; 767 } 768 769 *argc_p = argc; 770 *argv_p = argv; 771 return 0; 772} 773 774static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) 775{ 776 struct { 777 struct tc_u32_sel sel; 778 struct tc_u32_key keys[128]; 779 } sel; 780 struct tcmsg *t = NLMSG_DATA(n); 781 struct rtattr *tail; 782 int sel_ok = 0; 783 int sample_ok = 0; 784 __u32 htid = 0; 785 __u32 order = 0; 786 787 memset(&sel, 0, sizeof(sel)); 788 789 if (handle && get_u32_handle(&t->tcm_handle, handle)) { 790 fprintf(stderr, "Illegal filter ID\n"); 791 return -1; 792 } 793 794 if (argc == 0) 795 return 0; 796 797 tail = NLMSG_TAIL(n); 798 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); 799 800 while (argc > 0) { 801 if (matches(*argv, "match") == 0) { 802 NEXT_ARG(); 803 if (parse_selector(&argc, &argv, &sel.sel, n)) { 804 fprintf(stderr, "Illegal \"match\"\n"); 805 return -1; 806 } 807 sel_ok++; 808 continue; 809 } else if (matches(*argv, "offset") == 0) { 810 NEXT_ARG(); 811 if (parse_offset(&argc, &argv, &sel.sel)) { 812 fprintf(stderr, "Illegal \"offset\"\n"); 813 return -1; 814 } 815 continue; 816 } else if (matches(*argv, "hashkey") == 0) { 817 NEXT_ARG(); 818 if (parse_hashkey(&argc, &argv, &sel.sel)) { 819 fprintf(stderr, "Illegal \"hashkey\"\n"); 820 return -1; 821 } 822 continue; 823 } else if (matches(*argv, "classid") == 0 || 824 strcmp(*argv, "flowid") == 0) { 825 unsigned handle; 826 NEXT_ARG(); 827 if (get_tc_classid(&handle, *argv)) { 828 fprintf(stderr, "Illegal \"classid\"\n"); 829 return -1; 830 } 831 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4); 832 sel.sel.flags |= TC_U32_TERMINAL; 833 } else if (matches(*argv, "divisor") == 0) { 834 unsigned divisor; 835 NEXT_ARG(); 836 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 || 837 divisor > 0x100) { 838 fprintf(stderr, "Illegal \"divisor\"\n"); 839 return -1; 840 } 841 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4); 842 } else if (matches(*argv, "order") == 0) { 843 NEXT_ARG(); 844 if (get_u32(&order, *argv, 0)) { 845 fprintf(stderr, "Illegal \"order\"\n"); 846 return -1; 847 } 848 } else if (strcmp(*argv, "link") == 0) { 849 unsigned handle; 850 NEXT_ARG(); 851 if (get_u32_handle(&handle, *argv)) { 852 fprintf(stderr, "Illegal \"link\"\n"); 853 return -1; 854 } 855 if (handle && TC_U32_NODE(handle)) { 856 fprintf(stderr, "\"link\" must be a hash table.\n"); 857 return -1; 858 } 859 addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4); 860 } else if (strcmp(*argv, "ht") == 0) { 861 unsigned handle; 862 NEXT_ARG(); 863 if (get_u32_handle(&handle, *argv)) { 864 fprintf(stderr, "Illegal \"ht\"\n"); 865 return -1; 866 } 867 if (handle && TC_U32_NODE(handle)) { 868 fprintf(stderr, "\"ht\" must be a hash table.\n"); 869 return -1; 870 } 871 if (sample_ok) 872 htid = (htid&0xFF000)|(handle&0xFFF00000); 873 else 874 htid = (handle&0xFFFFF000); 875 } else if (strcmp(*argv, "sample") == 0) { 876 __u32 hash; 877 struct { 878 struct tc_u32_sel sel; 879 struct tc_u32_key keys[4]; 880 } sel2; 881 NEXT_ARG(); 882 if (parse_selector(&argc, &argv, &sel2.sel, n)) { 883 fprintf(stderr, "Illegal \"sample\"\n"); 884 return -1; 885 } 886 if (sel2.sel.nkeys != 1) { 887 fprintf(stderr, "\"sample\" must contain exactly ONE key.\n"); 888 return -1; 889 } 890 hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask; 891 hash ^= hash>>16; 892 hash ^= hash>>8; 893 htid = ((hash<<12)&0xFF000)|(htid&0xFFF00000); 894 sample_ok = 1; 895 continue; 896 } else if (strcmp(*argv, "indev") == 0) { 897 char ind[IFNAMSIZ + 1]; 898 memset(ind, 0, sizeof (ind)); 899 argc--; 900 argv++; 901 if (argc < 1) { 902 fprintf(stderr, "Illegal indev\n"); 903 return -1; 904 } 905 strncpy(ind, *argv, sizeof (ind) - 1); 906 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1); 907 908 } else if (matches(*argv, "action") == 0) { 909 NEXT_ARG(); 910 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) { 911 fprintf(stderr, "Illegal \"action\"\n"); 912 return -1; 913 } 914 continue; 915 916 } else if (matches(*argv, "police") == 0) { 917 NEXT_ARG(); 918 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) { 919 fprintf(stderr, "Illegal \"police\"\n"); 920 return -1; 921 } 922 continue; 923 } else if (strcmp(*argv, "help") == 0) { 924 explain(); 925 return -1; 926 } else { 927 fprintf(stderr, "What is \"%s\"?\n", *argv); 928 explain(); 929 return -1; 930 } 931 argc--; argv++; 932 } 933 934 if (order) { 935 if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) { 936 fprintf(stderr, "\"order\" contradicts \"handle\"\n"); 937 return -1; 938 } 939 t->tcm_handle |= order; 940 } 941 942 if (htid) 943 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4); 944 if (sel_ok) 945 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key)); 946 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 947 return 0; 948} 949 950static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle) 951{ 952 struct rtattr *tb[TCA_U32_MAX+1]; 953 struct tc_u32_sel *sel = NULL; 954 struct tc_u32_pcnt *pf = NULL; 955 956 if (opt == NULL) 957 return 0; 958 959 parse_rtattr_nested(tb, TCA_U32_MAX, opt); 960 961 if (handle) { 962 SPRINT_BUF(b1); 963 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1)); 964 } 965 if (TC_U32_NODE(handle)) { 966 fprintf(f, "order %d ", TC_U32_NODE(handle)); 967 } 968 969 if (tb[TCA_U32_SEL]) { 970 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel)) 971 return -1; 972 973 sel = RTA_DATA(tb[TCA_U32_SEL]); 974 } 975 976 if (tb[TCA_U32_DIVISOR]) { 977 fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR])); 978 } else if (tb[TCA_U32_HASH]) { 979 __u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]); 980 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid), TC_U32_HASH(htid)); 981 } else { 982 fprintf(f, "??? "); 983 } 984 if (tb[TCA_U32_CLASSID]) { 985 SPRINT_BUF(b1); 986 fprintf(f, "%sflowid %s ", 987 !sel || !(sel->flags&TC_U32_TERMINAL) ? "*" : "", 988 sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_U32_CLASSID]), b1)); 989 } else if (sel && sel->flags&TC_U32_TERMINAL) { 990 fprintf(f, "terminal flowid ??? "); 991 } 992 if (tb[TCA_U32_LINK]) { 993 SPRINT_BUF(b1); 994 fprintf(f, "link %s ", sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1)); 995 } 996 997 if (tb[TCA_U32_PCNT]) { 998 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) { 999 fprintf(f, "Broken perf counters \n"); 1000 return -1; 1001 } 1002 pf = RTA_DATA(tb[TCA_U32_PCNT]); 1003 } 1004 1005 if (sel && show_stats && NULL != pf) 1006 fprintf(f, " (rule hit %llu success %llu)", 1007 (unsigned long long) pf->rcnt, 1008 (unsigned long long) pf->rhit); 1009 1010 if (tb[TCA_U32_MARK]) { 1011 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]); 1012 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) { 1013 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n"); 1014 } else { 1015 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)", 1016 mark->val, mark->mask, mark->success); 1017 } 1018 } 1019 1020 if (sel) { 1021 int i; 1022 struct tc_u32_key *key = sel->keys; 1023 if (sel->nkeys) { 1024 for (i=0; i<sel->nkeys; i++, key++) { 1025 fprintf(f, "\n match %08x/%08x at %s%d", 1026 (unsigned int)ntohl(key->val), 1027 (unsigned int)ntohl(key->mask), 1028 key->offmask ? "nexthdr+" : "", 1029 key->off); 1030 if (show_stats && NULL != pf) 1031 fprintf(f, " (success %lld ) ", 1032 (unsigned long long) pf->kcnts[i]); 1033 } 1034 } 1035 1036 if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) { 1037 fprintf(f, "\n offset "); 1038 if (sel->flags&TC_U32_VAROFFSET) 1039 fprintf(f, "%04x>>%d at %d ", ntohs(sel->offmask), sel->offshift, sel->offoff); 1040 if (sel->off) 1041 fprintf(f, "plus %d ", sel->off); 1042 } 1043 if (sel->flags&TC_U32_EAT) 1044 fprintf(f, " eat "); 1045 1046 if (sel->hmask) { 1047 fprintf(f, "\n hash mask %08x at %d ", 1048 (unsigned int)htonl(sel->hmask), sel->hoff); 1049 } 1050 } 1051 1052 if (tb[TCA_U32_POLICE]) { 1053 fprintf(f, "\n"); 1054 tc_print_police(f, tb[TCA_U32_POLICE]); 1055 } 1056 if (tb[TCA_U32_INDEV]) { 1057 struct rtattr *idev = tb[TCA_U32_INDEV]; 1058 fprintf(f, "\n input dev %s\n", (char *) RTA_DATA(idev)); 1059 } 1060 if (tb[TCA_U32_ACT]) { 1061 tc_print_action(f, tb[TCA_U32_ACT]); 1062 } 1063 1064 return 0; 1065} 1066 1067struct filter_util u32_filter_util = { 1068 .id = "u32", 1069 .parse_fopt = u32_parse_opt, 1070 .print_fopt = u32_print_opt, 1071}; 1072