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