iproute2/tc/f_u32.c
<<
>>
Prefs
   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 <fcntl.h>
  18#include <sys/socket.h>
  19#include <netinet/in.h>
  20#include <arpa/inet.h>
  21#include <string.h>
  22#include <linux/if.h>
  23#include <linux/if_ether.h>
  24
  25#include "utils.h"
  26#include "tc_util.h"
  27
  28static void explain(void)
  29{
  30        fprintf(stderr,
  31                "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"
  32                "               [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"
  33                "               [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"
  34                "               [ sample SAMPLE ] [skip_hw | skip_sw]\n"
  35                "or         u32 divisor DIVISOR\n"
  36                "\n"
  37                "Where: SELECTOR := SAMPLE SAMPLE ...\n"
  38                "       SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n"
  39                "                 SAMPLE_ARGS [ divisor DIVISOR ]\n"
  40                "       FILTERID := X:Y:Z\n"
  41                "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
  42}
  43
  44static int get_u32_handle(__u32 *handle, const char *str)
  45{
  46        __u32 htid = 0, hash = 0, nodeid = 0;
  47        char *tmp = strchr(str, ':');
  48
  49        if (tmp == NULL) {
  50                if (memcmp("0x", str, 2) == 0)
  51                        return get_u32(handle, str, 16);
  52                return -1;
  53        }
  54        htid = strtoul(str, &tmp, 16);
  55        if (tmp == str && *str != ':' && *str != 0)
  56                return -1;
  57        if (htid >= 0x1000)
  58                return -1;
  59        if (*tmp) {
  60                str = tmp + 1;
  61                hash = strtoul(str, &tmp, 16);
  62                if (tmp == str && *str != ':' && *str != 0)
  63                        return -1;
  64                if (hash >= 0x100)
  65                        return -1;
  66                if (*tmp) {
  67                        str = tmp + 1;
  68                        nodeid = strtoul(str, &tmp, 16);
  69                        if (tmp == str && *str != 0)
  70                                return -1;
  71                        if (nodeid >= 0x1000)
  72                                return -1;
  73                }
  74        }
  75        *handle = (htid<<20)|(hash<<12)|nodeid;
  76        return 0;
  77}
  78
  79static char *sprint_u32_handle(__u32 handle, char *buf)
  80{
  81        int bsize = SPRINT_BSIZE-1;
  82        __u32 htid = TC_U32_HTID(handle);
  83        __u32 hash = TC_U32_HASH(handle);
  84        __u32 nodeid = TC_U32_NODE(handle);
  85        char *b = buf;
  86
  87        if (handle == 0) {
  88                snprintf(b, bsize, "none");
  89                return b;
  90        }
  91        if (htid) {
  92                int l = snprintf(b, bsize, "%x:", htid>>20);
  93
  94                bsize -= l;
  95                b += l;
  96        }
  97        if (nodeid|hash) {
  98                if (hash) {
  99                        int l = snprintf(b, bsize, "%x", hash);
 100
 101                        bsize -= l;
 102                        b += l;
 103                }
 104                if (nodeid) {
 105                        int l = snprintf(b, bsize, ":%x", nodeid);
 106
 107                        bsize -= l;
 108                        b += l;
 109                }
 110        }
 111        if (show_raw)
 112                snprintf(b, bsize, "[%08x] ", handle);
 113        return buf;
 114}
 115
 116static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
 117                    int off, int offmask)
 118{
 119        int i;
 120        int hwm = sel->nkeys;
 121
 122        key &= mask;
 123
 124        for (i = 0; i < hwm; i++) {
 125                if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
 126                        __u32 intersect = mask & sel->keys[i].mask;
 127
 128                        if ((key ^ sel->keys[i].val) & intersect)
 129                                return -1;
 130                        sel->keys[i].val |= key;
 131                        sel->keys[i].mask |= mask;
 132                        return 0;
 133                }
 134        }
 135
 136        if (hwm >= 128)
 137                return -1;
 138        if (off % 4)
 139                return -1;
 140        sel->keys[hwm].val = key;
 141        sel->keys[hwm].mask = mask;
 142        sel->keys[hwm].off = off;
 143        sel->keys[hwm].offmask = offmask;
 144        sel->nkeys++;
 145        return 0;
 146}
 147
 148static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
 149                      int off, int offmask)
 150{
 151        key = htonl(key);
 152        mask = htonl(mask);
 153        return pack_key(sel, key, mask, off, offmask);
 154}
 155
 156static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
 157                      int off, int offmask)
 158{
 159        if (key > 0xFFFF || mask > 0xFFFF)
 160                return -1;
 161
 162        if ((off & 3) == 0) {
 163                key <<= 16;
 164                mask <<= 16;
 165        }
 166        off &= ~3;
 167        key = htonl(key);
 168        mask = htonl(mask);
 169
 170        return pack_key(sel, key, mask, off, offmask);
 171}
 172
 173static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off,
 174                     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
 197static 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
 226static 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
 258static 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
 289static 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
 324static 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
 359static 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 < plen) {
 386                        res = pack_key(sel, addr.data[i / 32],
 387                                       0xFFFFFFFF, off + 4 * (i / 32), offmask);
 388                        if (res < 0)
 389                                return -1;
 390                } else if (i < plen) {
 391                        __u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i)));
 392
 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
 406static 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
 444static 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
 483static 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            matches(*argv, "precedence") == 0) {
 501                NEXT_ARG();
 502                res = parse_u8(&argc, &argv, sel, 1, 0);
 503        } else if (strcmp(*argv, "ihl") == 0) {
 504                NEXT_ARG();
 505                res = parse_u8(&argc, &argv, sel, 0, 0);
 506        } else if (strcmp(*argv, "protocol") == 0) {
 507                NEXT_ARG();
 508                res = parse_u8(&argc, &argv, sel, 9, 0);
 509        } else if (strcmp(*argv, "nofrag") == 0) {
 510                argc--; argv++;
 511                res = pack_key16(sel, 0, 0x3FFF, 6, 0);
 512        } else if (strcmp(*argv, "firstfrag") == 0) {
 513                argc--; argv++;
 514                res = pack_key16(sel, 0x2000, 0x3FFF, 6, 0);
 515        } else if (strcmp(*argv, "df") == 0) {
 516                argc--; argv++;
 517                res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
 518        } else if (strcmp(*argv, "mf") == 0) {
 519                argc--; argv++;
 520                res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
 521        } else if (strcmp(*argv, "dport") == 0) {
 522                NEXT_ARG();
 523                res = parse_u16(&argc, &argv, sel, 22, 0);
 524        } else if (strcmp(*argv, "sport") == 0) {
 525                NEXT_ARG();
 526                res = parse_u16(&argc, &argv, sel, 20, 0);
 527        } else if (strcmp(*argv, "icmp_type") == 0) {
 528                NEXT_ARG();
 529                res = parse_u8(&argc, &argv, sel, 20, 0);
 530        } else if (strcmp(*argv, "icmp_code") == 0) {
 531                NEXT_ARG();
 532                res = parse_u8(&argc, &argv, sel, 21, 0);
 533        } else
 534                return -1;
 535
 536        *argc_p = argc;
 537        *argv_p = argv;
 538        return res;
 539}
 540
 541static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 542{
 543        int res = -1;
 544        int argc = *argc_p;
 545        char **argv = *argv_p;
 546
 547        if (argc < 2)
 548                return -1;
 549
 550        if (strcmp(*argv, "src") == 0) {
 551                NEXT_ARG();
 552                res = parse_ip6_addr(&argc, &argv, sel, 8);
 553        } else if (strcmp(*argv, "dst") == 0) {
 554                NEXT_ARG();
 555                res = parse_ip6_addr(&argc, &argv, sel, 24);
 556        } else if (strcmp(*argv, "priority") == 0) {
 557                NEXT_ARG();
 558                res = parse_ip6_class(&argc, &argv, sel);
 559        } else if (strcmp(*argv, "protocol") == 0) {
 560                NEXT_ARG();
 561                res = parse_u8(&argc, &argv, sel, 6, 0);
 562        } else if (strcmp(*argv, "flowlabel") == 0) {
 563                NEXT_ARG();
 564                res = parse_u32(&argc, &argv, sel, 0, 0);
 565        } else if (strcmp(*argv, "dport") == 0) {
 566                NEXT_ARG();
 567                res = parse_u16(&argc, &argv, sel, 42, 0);
 568        } else if (strcmp(*argv, "sport") == 0) {
 569                NEXT_ARG();
 570                res = parse_u16(&argc, &argv, sel, 40, 0);
 571        } else if (strcmp(*argv, "icmp_type") == 0) {
 572                NEXT_ARG();
 573                res = parse_u8(&argc, &argv, sel, 40, 0);
 574        } else if (strcmp(*argv, "icmp_code") == 0) {
 575                NEXT_ARG();
 576                res = parse_u8(&argc, &argv, sel, 41, 1);
 577        } else
 578                return -1;
 579
 580        *argc_p = argc;
 581        *argv_p = argv;
 582        return res;
 583}
 584
 585static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 586{
 587        int res = -1;
 588        int argc = *argc_p;
 589        char **argv = *argv_p;
 590
 591        if (argc < 2)
 592                return -1;
 593
 594        if (strcmp(*argv, "src") == 0) {
 595                NEXT_ARG();
 596                res = parse_ether_addr(&argc, &argv, sel, -8);
 597        } else if (strcmp(*argv, "dst") == 0) {
 598                NEXT_ARG();
 599                res = parse_ether_addr(&argc, &argv, sel, -14);
 600        } else {
 601                fprintf(stderr, "Unknown match: ether %s\n", *argv);
 602                return -1;
 603        }
 604
 605        *argc_p = argc;
 606        *argv_p = argv;
 607        return res;
 608}
 609
 610#define parse_tcp parse_udp
 611static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 612{
 613        int res = -1;
 614        int argc = *argc_p;
 615        char **argv = *argv_p;
 616
 617        if (argc < 2)
 618                return -1;
 619
 620        if (strcmp(*argv, "src") == 0) {
 621                NEXT_ARG();
 622                res = parse_u16(&argc, &argv, sel, 0, -1);
 623        } else if (strcmp(*argv, "dst") == 0) {
 624                NEXT_ARG();
 625                res = parse_u16(&argc, &argv, sel, 2, -1);
 626        } else
 627                return -1;
 628
 629        *argc_p = argc;
 630        *argv_p = argv;
 631        return res;
 632}
 633
 634
 635static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 636{
 637        int res = -1;
 638        int argc = *argc_p;
 639        char **argv = *argv_p;
 640
 641        if (argc < 2)
 642                return -1;
 643
 644        if (strcmp(*argv, "type") == 0) {
 645                NEXT_ARG();
 646                res = parse_u8(&argc, &argv, sel, 0, -1);
 647        } else if (strcmp(*argv, "code") == 0) {
 648                NEXT_ARG();
 649                res = parse_u8(&argc, &argv, sel, 1, -1);
 650        } else
 651                return -1;
 652
 653        *argc_p = argc;
 654        *argv_p = argv;
 655        return res;
 656}
 657
 658static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
 659{
 660        int res = -1;
 661        int argc = *argc_p;
 662        char **argv = *argv_p;
 663        struct tc_u32_mark mark;
 664
 665        if (argc <= 1)
 666                return -1;
 667
 668        if (get_u32(&mark.val, *argv, 0)) {
 669                fprintf(stderr, "Illegal \"mark\" value\n");
 670                return -1;
 671        }
 672        NEXT_ARG();
 673
 674        if (get_u32(&mark.mask, *argv, 0)) {
 675                fprintf(stderr, "Illegal \"mark\" mask\n");
 676                return -1;
 677        }
 678        NEXT_ARG();
 679
 680        if ((mark.val & mark.mask) != mark.val) {
 681                fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
 682                return -1;
 683        }
 684
 685        addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
 686        res = 0;
 687
 688        *argc_p = argc;
 689        *argv_p = argv;
 690        return res;
 691}
 692
 693static int parse_selector(int *argc_p, char ***argv_p,
 694                          struct tc_u32_sel *sel, struct nlmsghdr *n)
 695{
 696        int argc = *argc_p;
 697        char **argv = *argv_p;
 698        int res = -1;
 699
 700        if (argc <= 0)
 701                return -1;
 702
 703        if (matches(*argv, "u32") == 0) {
 704                NEXT_ARG();
 705                res = parse_u32(&argc, &argv, sel, 0, 0);
 706        } else if (matches(*argv, "u16") == 0) {
 707                NEXT_ARG();
 708                res = parse_u16(&argc, &argv, sel, 0, 0);
 709        } else if (matches(*argv, "u8") == 0) {
 710                NEXT_ARG();
 711                res = parse_u8(&argc, &argv, sel, 0, 0);
 712        } else if (matches(*argv, "ip") == 0) {
 713                NEXT_ARG();
 714                res = parse_ip(&argc, &argv, sel);
 715        } else  if (matches(*argv, "ip6") == 0) {
 716                NEXT_ARG();
 717                res = parse_ip6(&argc, &argv, sel);
 718        } else if (matches(*argv, "udp") == 0) {
 719                NEXT_ARG();
 720                res = parse_udp(&argc, &argv, sel);
 721        } else if (matches(*argv, "tcp") == 0) {
 722                NEXT_ARG();
 723                res = parse_tcp(&argc, &argv, sel);
 724        } else if (matches(*argv, "icmp") == 0) {
 725                NEXT_ARG();
 726                res = parse_icmp(&argc, &argv, sel);
 727        } else if (matches(*argv, "mark") == 0) {
 728                NEXT_ARG();
 729                res = parse_mark(&argc, &argv, n);
 730        } else if (matches(*argv, "ether") == 0) {
 731                NEXT_ARG();
 732                res = parse_ether(&argc, &argv, sel);
 733        } else
 734                return -1;
 735
 736        *argc_p = argc;
 737        *argv_p = argv;
 738        return res;
 739}
 740
 741static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 742{
 743        int argc = *argc_p;
 744        char **argv = *argv_p;
 745
 746        while (argc > 0) {
 747                if (matches(*argv, "plus") == 0) {
 748                        int off;
 749
 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
 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                        NEXT_ARG();
 769                        if (get_be16(&sel->offmask, *argv, 16))
 770                                return -1;
 771                        sel->flags |= TC_U32_VAROFFSET;
 772                } else if (matches(*argv, "shift") == 0) {
 773                        int shift;
 774
 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
 793static 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                        NEXT_ARG();
 801                        if (get_be32(&sel->hmask, *argv, 16))
 802                                return -1;
 803                } else if (matches(*argv, "at") == 0) {
 804                        int num;
 805
 806                        NEXT_ARG();
 807                        if (get_integer(&num, *argv, 0))
 808                                return -1;
 809                        if (num%4)
 810                                return -1;
 811                        sel->hoff = num;
 812                } else {
 813                        break;
 814                }
 815                argc--; argv++;
 816        }
 817
 818        *argc_p = argc;
 819        *argv_p = argv;
 820        return 0;
 821}
 822
 823static void print_ipv4(FILE *f, const struct tc_u32_key *key)
 824{
 825        char abuf[256];
 826
 827        switch (key->off) {
 828        case 0:
 829                switch (ntohl(key->mask)) {
 830                case 0x0f000000:
 831                        fprintf(f, "\n  match IP ihl %u",
 832                                ntohl(key->val) >> 24);
 833                        return;
 834                case 0x00ff0000:
 835                        fprintf(f, "\n  match IP dsfield %#x",
 836                                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",
 843                                ntohl(key->val) >> 16);
 844                        return;
 845                }
 846                break;
 847        case 12:
 848        case 16: {
 849                        int bits = mask2bits(key->mask);
 850
 851                        if (bits >= 0) {
 852                                fprintf(f, "\n  %s %s/%d",
 853                                        key->off == 12 ? "match IP src" : "match IP dst",
 854                                        inet_ntop(AF_INET, &key->val,
 855                                                  abuf, sizeof(abuf)),
 856                                        bits);
 857                                return;
 858                        }
 859                }
 860                break;
 861
 862        case 20:
 863                switch (ntohl(key->mask)) {
 864                case 0x0000ffff:
 865                        fprintf(f, "\n  match dport %u",
 866                                ntohl(key->val) & 0xffff);
 867                        return;
 868                case 0xffff0000:
 869                        fprintf(f, "\n  match sport %u",
 870                                ntohl(key->val) >> 16);
 871                        return;
 872                case 0xffffffff:
 873                        fprintf(f, "\n  match dport %u, match sport %u",
 874                                ntohl(key->val) & 0xffff,
 875                                ntohl(key->val) >> 16);
 876
 877                        return;
 878                }
 879                /* XXX: Default print_raw */
 880        }
 881}
 882
 883static void print_ipv6(FILE *f, const struct tc_u32_key *key)
 884{
 885        char abuf[256];
 886
 887        switch (key->off) {
 888        case 0:
 889                switch (ntohl(key->mask)) {
 890                case 0x0f000000:
 891                        fprintf(f, "\n  match IP ihl %u",
 892                                ntohl(key->val) >> 24);
 893                        return;
 894                case 0x00ff0000:
 895                        fprintf(f, "\n  match IP dsfield %#x",
 896                                ntohl(key->val) >> 16);
 897                        return;
 898                }
 899                break;
 900        case 8:
 901                if (ntohl(key->mask) == 0x00ff0000) {
 902                        fprintf(f, "\n  match IP protocol %d",
 903                                ntohl(key->val) >> 16);
 904                        return;
 905                }
 906                break;
 907        case 12:
 908        case 16: {
 909                        int bits = mask2bits(key->mask);
 910
 911                        if (bits >= 0) {
 912                                fprintf(f, "\n  %s %s/%d",
 913                                        key->off == 12 ? "match IP src" : "match IP dst",
 914                                        inet_ntop(AF_INET, &key->val,
 915                                                  abuf, sizeof(abuf)),
 916                                        bits);
 917                                return;
 918                        }
 919                }
 920                break;
 921
 922        case 20:
 923                switch (ntohl(key->mask)) {
 924                case 0x0000ffff:
 925                        fprintf(f, "\n  match sport %u",
 926                                ntohl(key->val) & 0xffff);
 927                        return;
 928                case 0xffff0000:
 929                        fprintf(f, "\n  match dport %u",
 930                                ntohl(key->val) >> 16);
 931                        return;
 932                case 0xffffffff:
 933                        fprintf(f, "\n  match sport %u, match dport %u",
 934                                ntohl(key->val) & 0xffff,
 935                                ntohl(key->val) >> 16);
 936
 937                        return;
 938                }
 939                /* XXX: Default print_raw */
 940        }
 941}
 942
 943static void print_raw(FILE *f, const struct tc_u32_key *key)
 944{
 945        fprintf(f, "\n  match %08x/%08x at %s%d",
 946                (unsigned int)ntohl(key->val),
 947                (unsigned int)ntohl(key->mask),
 948                key->offmask ? "nexthdr+" : "",
 949                key->off);
 950}
 951
 952static const struct {
 953        __u16 proto;
 954        __u16 pad;
 955        void (*pprinter)(FILE *f, const struct tc_u32_key *key);
 956} u32_pprinters[] = {
 957        {0,        0, print_raw},
 958        {ETH_P_IP, 0, print_ipv4},
 959        {ETH_P_IPV6, 0, print_ipv6},
 960};
 961
 962static void show_keys(FILE *f, const struct tc_u32_key *key)
 963{
 964        int i = 0;
 965
 966        if (!pretty)
 967                goto show_k;
 968
 969        for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
 970                if (u32_pprinters[i].proto == ntohs(f_proto)) {
 971show_k:
 972                        u32_pprinters[i].pprinter(f, key);
 973                        return;
 974                }
 975        }
 976
 977        i = 0;
 978        goto show_k;
 979}
 980
 981static int u32_parse_opt(struct filter_util *qu, char *handle,
 982                         int argc, char **argv, struct nlmsghdr *n)
 983{
 984        struct {
 985                struct tc_u32_sel sel;
 986                struct tc_u32_key keys[128];
 987        } sel = {};
 988        struct tcmsg *t = NLMSG_DATA(n);
 989        struct rtattr *tail;
 990        int sel_ok = 0, terminal_ok = 0;
 991        int sample_ok = 0;
 992        __u32 htid = 0;
 993        __u32 order = 0;
 994        __u32 flags = 0;
 995
 996        if (handle && get_u32_handle(&t->tcm_handle, handle)) {
 997                fprintf(stderr, "Illegal filter ID\n");
 998                return -1;
 999        }
1000
1001        if (argc == 0)
1002                return 0;
1003
1004        tail = addattr_nest(n, MAX_MSG, TCA_OPTIONS);
1005
1006        while (argc > 0) {
1007                if (matches(*argv, "match") == 0) {
1008                        NEXT_ARG();
1009                        if (parse_selector(&argc, &argv, &sel.sel, n)) {
1010                                fprintf(stderr, "Illegal \"match\"\n");
1011                                return -1;
1012                        }
1013                        sel_ok++;
1014                        continue;
1015                } else if (matches(*argv, "offset") == 0) {
1016                        NEXT_ARG();
1017                        if (parse_offset(&argc, &argv, &sel.sel)) {
1018                                fprintf(stderr, "Illegal \"offset\"\n");
1019                                return -1;
1020                        }
1021                        continue;
1022                } else if (matches(*argv, "hashkey") == 0) {
1023                        NEXT_ARG();
1024                        if (parse_hashkey(&argc, &argv, &sel.sel)) {
1025                                fprintf(stderr, "Illegal \"hashkey\"\n");
1026                                return -1;
1027                        }
1028                        continue;
1029                } else if (matches(*argv, "classid") == 0 ||
1030                           strcmp(*argv, "flowid") == 0) {
1031                        unsigned int flowid;
1032
1033                        NEXT_ARG();
1034                        if (get_tc_classid(&flowid, *argv)) {
1035                                fprintf(stderr, "Illegal \"classid\"\n");
1036                                return -1;
1037                        }
1038                        addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4);
1039                        sel.sel.flags |= TC_U32_TERMINAL;
1040                } else if (matches(*argv, "divisor") == 0) {
1041                        unsigned int divisor;
1042
1043                        NEXT_ARG();
1044                        if (get_unsigned(&divisor, *argv, 0) ||
1045                            divisor == 0 ||
1046                            divisor > 0x100 || ((divisor - 1) & divisor)) {
1047                                fprintf(stderr, "Illegal \"divisor\"\n");
1048                                return -1;
1049                        }
1050                        addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
1051                } else if (matches(*argv, "order") == 0) {
1052                        NEXT_ARG();
1053                        if (get_u32(&order, *argv, 0)) {
1054                                fprintf(stderr, "Illegal \"order\"\n");
1055                                return -1;
1056                        }
1057                } else if (strcmp(*argv, "link") == 0) {
1058                        unsigned int linkid;
1059
1060                        NEXT_ARG();
1061                        if (get_u32_handle(&linkid, *argv)) {
1062                                fprintf(stderr, "Illegal \"link\"\n");
1063                                return -1;
1064                        }
1065                        if (linkid && TC_U32_NODE(linkid)) {
1066                                fprintf(stderr, "\"link\" must be a hash table.\n");
1067                                return -1;
1068                        }
1069                        addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4);
1070                } else if (strcmp(*argv, "ht") == 0) {
1071                        unsigned int ht;
1072
1073                        NEXT_ARG();
1074                        if (get_u32_handle(&ht, *argv)) {
1075                                fprintf(stderr, "Illegal \"ht\"\n");
1076                                return -1;
1077                        }
1078                        if (handle && TC_U32_NODE(ht)) {
1079                                fprintf(stderr, "\"ht\" must be a hash table.\n");
1080                                return -1;
1081                        }
1082                        if (sample_ok)
1083                                htid = (htid & 0xFF000) | (ht & 0xFFF00000);
1084                        else
1085                                htid = (ht & 0xFFFFF000);
1086                } else if (strcmp(*argv, "sample") == 0) {
1087                        __u32 hash;
1088                        unsigned int divisor = 0x100;
1089                        struct {
1090                                struct tc_u32_sel sel;
1091                                struct tc_u32_key keys[4];
1092                        } sel2 = {};
1093
1094                        NEXT_ARG();
1095                        if (parse_selector(&argc, &argv, &sel2.sel, n)) {
1096                                fprintf(stderr, "Illegal \"sample\"\n");
1097                                return -1;
1098                        }
1099                        if (sel2.sel.nkeys != 1) {
1100                                fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
1101                                return -1;
1102                        }
1103                        if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1104                                NEXT_ARG();
1105                                if (get_unsigned(&divisor, *argv, 0) ||
1106                                    divisor == 0 || divisor > 0x100 ||
1107                                    ((divisor - 1) & divisor)) {
1108                                        fprintf(stderr, "Illegal sample \"divisor\"\n");
1109                                        return -1;
1110                                }
1111                                NEXT_ARG();
1112                        }
1113                        hash = sel2.keys[0].val & sel2.keys[0].mask;
1114                        hash ^= hash >> 16;
1115                        hash ^= hash >> 8;
1116                        htid = ((hash % divisor) << 12) | (htid & 0xFFF00000);
1117                        sample_ok = 1;
1118                        continue;
1119                } else if (strcmp(*argv, "indev") == 0) {
1120                        char ind[IFNAMSIZ + 1] = {};
1121
1122                        argc--;
1123                        argv++;
1124                        if (argc < 1) {
1125                                fprintf(stderr, "Illegal indev\n");
1126                                return -1;
1127                        }
1128                        strncpy(ind, *argv, sizeof(ind) - 1);
1129                        addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind,
1130                                  strlen(ind) + 1);
1131
1132                } else if (matches(*argv, "action") == 0) {
1133                        NEXT_ARG();
1134                        if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1135                                fprintf(stderr, "Illegal \"action\"\n");
1136                                return -1;
1137                        }
1138                        terminal_ok++;
1139                        continue;
1140
1141                } else if (matches(*argv, "police") == 0) {
1142                        NEXT_ARG();
1143                        if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1144                                fprintf(stderr, "Illegal \"police\"\n");
1145                                return -1;
1146                        }
1147                        terminal_ok++;
1148                        continue;
1149                } else if (strcmp(*argv, "skip_hw") == 0) {
1150                        flags |= TCA_CLS_FLAGS_SKIP_HW;
1151                } else if (strcmp(*argv, "skip_sw") == 0) {
1152                        flags |= TCA_CLS_FLAGS_SKIP_SW;
1153                } else if (strcmp(*argv, "help") == 0) {
1154                        explain();
1155                        return -1;
1156                } else {
1157                        fprintf(stderr, "What is \"%s\"?\n", *argv);
1158                        explain();
1159                        return -1;
1160                }
1161                argc--; argv++;
1162        }
1163
1164        /* We don't necessarily need class/flowids */
1165        if (terminal_ok)
1166                sel.sel.flags |= TC_U32_TERMINAL;
1167
1168        if (order) {
1169                if (TC_U32_NODE(t->tcm_handle) &&
1170                    order != TC_U32_NODE(t->tcm_handle)) {
1171                        fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1172                        return -1;
1173                }
1174                t->tcm_handle |= order;
1175        }
1176
1177        if (htid)
1178                addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
1179        if (sel_ok)
1180                addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
1181                          sizeof(sel.sel) +
1182                          sel.sel.nkeys * sizeof(struct tc_u32_key));
1183        if (flags) {
1184                if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW |
1185                               TCA_CLS_FLAGS_SKIP_SW))) {
1186                        fprintf(stderr,
1187                                "skip_hw and skip_sw are mutually exclusive\n");
1188                        return -1;
1189                }
1190                addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
1191        }
1192
1193        addattr_nest_end(n, tail);
1194        return 0;
1195}
1196
1197static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1198                         __u32 handle)
1199{
1200        struct rtattr *tb[TCA_U32_MAX + 1];
1201        struct tc_u32_sel *sel = NULL;
1202        struct tc_u32_pcnt *pf = NULL;
1203
1204        if (opt == NULL)
1205                return 0;
1206
1207        parse_rtattr_nested(tb, TCA_U32_MAX, opt);
1208
1209        if (handle) {
1210                SPRINT_BUF(b1);
1211                fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1212        }
1213
1214        if (TC_U32_NODE(handle))
1215                fprintf(f, "order %d ", TC_U32_NODE(handle));
1216
1217        if (tb[TCA_U32_SEL]) {
1218                if (RTA_PAYLOAD(tb[TCA_U32_SEL])  < sizeof(*sel))
1219                        return -1;
1220
1221                sel = RTA_DATA(tb[TCA_U32_SEL]);
1222        }
1223
1224        if (tb[TCA_U32_DIVISOR]) {
1225                fprintf(f, "ht divisor %d ",
1226                        rta_getattr_u32(tb[TCA_U32_DIVISOR]));
1227        } else if (tb[TCA_U32_HASH]) {
1228                __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]);
1229
1230                fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1231                        TC_U32_HASH(htid));
1232        } else {
1233                fprintf(f, "??? ");
1234        }
1235        if (tb[TCA_U32_CLASSID]) {
1236                SPRINT_BUF(b1);
1237                fprintf(f, "%sflowid %s ",
1238                        !sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "",
1239                        sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]),
1240                                          b1));
1241        } else if (sel && sel->flags & TC_U32_TERMINAL) {
1242                fprintf(f, "terminal flowid ??? ");
1243        }
1244        if (tb[TCA_U32_LINK]) {
1245                SPRINT_BUF(b1);
1246                fprintf(f, "link %s ",
1247                        sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]),
1248                                          b1));
1249        }
1250
1251        if (tb[TCA_U32_FLAGS]) {
1252                __u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]);
1253
1254                if (flags & TCA_CLS_FLAGS_SKIP_HW)
1255                        fprintf(f, "skip_hw ");
1256                if (flags & TCA_CLS_FLAGS_SKIP_SW)
1257                        fprintf(f, "skip_sw ");
1258
1259                if (flags & TCA_CLS_FLAGS_IN_HW)
1260                        fprintf(f, "in_hw ");
1261                else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
1262                        fprintf(f, "not_in_hw ");
1263        }
1264
1265        if (tb[TCA_U32_PCNT]) {
1266                if (RTA_PAYLOAD(tb[TCA_U32_PCNT])  < sizeof(*pf)) {
1267                        fprintf(f, "Broken perf counters\n");
1268                        return -1;
1269                }
1270                pf = RTA_DATA(tb[TCA_U32_PCNT]);
1271        }
1272
1273        if (sel && show_stats && NULL != pf)
1274                fprintf(f, " (rule hit %llu success %llu)",
1275                        (unsigned long long) pf->rcnt,
1276                        (unsigned long long) pf->rhit);
1277
1278        if (tb[TCA_U32_MARK]) {
1279                struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1280
1281                if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1282                        fprintf(f, "\n  Invalid mark (kernel&iproute2 mismatch)\n");
1283                } else {
1284                        fprintf(f, "\n  mark 0x%04x 0x%04x (success %d)",
1285                                mark->val, mark->mask, mark->success);
1286                }
1287        }
1288
1289        if (sel) {
1290                if (sel->nkeys) {
1291                        int i;
1292
1293                        for (i = 0; i < sel->nkeys; i++) {
1294                                show_keys(f, sel->keys + i);
1295                                if (show_stats && NULL != pf)
1296                                        fprintf(f, " (success %llu ) ",
1297                                                (unsigned long long) pf->kcnts[i]);
1298                        }
1299                }
1300
1301                if (sel->flags & (TC_U32_VAROFFSET | TC_U32_OFFSET)) {
1302                        fprintf(f, "\n    offset ");
1303                        if (sel->flags & TC_U32_VAROFFSET)
1304                                fprintf(f, "%04x>>%d at %d ",
1305                                        ntohs(sel->offmask),
1306                                        sel->offshift,  sel->offoff);
1307                        if (sel->off)
1308                                fprintf(f, "plus %d ", sel->off);
1309                }
1310                if (sel->flags & TC_U32_EAT)
1311                        fprintf(f, " eat ");
1312
1313                if (sel->hmask) {
1314                        fprintf(f, "\n    hash mask %08x at %d ",
1315                                (unsigned int)htonl(sel->hmask), sel->hoff);
1316                }
1317        }
1318
1319        if (tb[TCA_U32_POLICE]) {
1320                fprintf(f, "\n");
1321                tc_print_police(f, tb[TCA_U32_POLICE]);
1322        }
1323
1324        if (tb[TCA_U32_INDEV]) {
1325                struct rtattr *idev = tb[TCA_U32_INDEV];
1326
1327                fprintf(f, "\n  input dev %s\n", rta_getattr_str(idev));
1328        }
1329
1330        if (tb[TCA_U32_ACT])
1331                tc_print_action(f, tb[TCA_U32_ACT], 0);
1332
1333        return 0;
1334}
1335
1336struct filter_util u32_filter_util = {
1337        .id = "u32",
1338        .parse_fopt = u32_parse_opt,
1339        .print_fopt = u32_print_opt,
1340};
1341