linux/net/sched/cls_rsvp.h
<<
>>
Prefs
   1/*
   2 * net/sched/cls_rsvp.h Template file for RSVPv[46] classifiers.
   3 *
   4 *              This program is free software; you can redistribute 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   Comparing to general packet classification problem,
  14   RSVP needs only sevaral relatively simple rules:
  15
  16   * (dst, protocol) are always specified,
  17     so that we are able to hash them.
  18   * src may be exact, or may be wildcard, so that
  19     we can keep a hash table plus one wildcard entry.
  20   * source port (or flow label) is important only if src is given.
  21
  22   IMPLEMENTATION.
  23
  24   We use a two level hash table: The top level is keyed by
  25   destination address and protocol ID, every bucket contains a list
  26   of "rsvp sessions", identified by destination address, protocol and
  27   DPI(="Destination Port ID"): triple (key, mask, offset).
  28
  29   Every bucket has a smaller hash table keyed by source address
  30   (cf. RSVP flowspec) and one wildcard entry for wildcard reservations.
  31   Every bucket is again a list of "RSVP flows", selected by
  32   source address and SPI(="Source Port ID" here rather than
  33   "security parameter index"): triple (key, mask, offset).
  34
  35
  36   NOTE 1. All the packets with IPv6 extension headers (but AH and ESP)
  37   and all fragmented packets go to the best-effort traffic class.
  38
  39
  40   NOTE 2. Two "port id"'s seems to be redundant, rfc2207 requires
  41   only one "Generalized Port Identifier". So that for classic
  42   ah, esp (and udp,tcp) both *pi should coincide or one of them
  43   should be wildcard.
  44
  45   At first sight, this redundancy is just a waste of CPU
  46   resources. But DPI and SPI add the possibility to assign different
  47   priorities to GPIs. Look also at note 4 about tunnels below.
  48
  49
  50   NOTE 3. One complication is the case of tunneled packets.
  51   We implement it as following: if the first lookup
  52   matches a special session with "tunnelhdr" value not zero,
  53   flowid doesn't contain the true flow ID, but the tunnel ID (1...255).
  54   In this case, we pull tunnelhdr bytes and restart lookup
  55   with tunnel ID added to the list of keys. Simple and stupid 8)8)
  56   It's enough for PIMREG and IPIP.
  57
  58
  59   NOTE 4. Two GPIs make it possible to parse even GRE packets.
  60   F.e. DPI can select ETH_P_IP (and necessary flags to make
  61   tunnelhdr correct) in GRE protocol field and SPI matches
  62   GRE key. Is it not nice? 8)8)
  63
  64
  65   Well, as result, despite its simplicity, we get a pretty
  66   powerful classification engine.  */
  67
  68
  69struct rsvp_head {
  70        u32                     tmap[256/32];
  71        u32                     hgenerator;
  72        u8                      tgenerator;
  73        struct rsvp_session __rcu *ht[256];
  74        struct rcu_head         rcu;
  75};
  76
  77struct rsvp_session {
  78        struct rsvp_session __rcu       *next;
  79        __be32                          dst[RSVP_DST_LEN];
  80        struct tc_rsvp_gpi              dpi;
  81        u8                              protocol;
  82        u8                              tunnelid;
  83        /* 16 (src,sport) hash slots, and one wildcard source slot */
  84        struct rsvp_filter __rcu        *ht[16 + 1];
  85        struct rcu_head                 rcu;
  86};
  87
  88
  89struct rsvp_filter {
  90        struct rsvp_filter __rcu        *next;
  91        __be32                          src[RSVP_DST_LEN];
  92        struct tc_rsvp_gpi              spi;
  93        u8                              tunnelhdr;
  94
  95        struct tcf_result               res;
  96        struct tcf_exts                 exts;
  97
  98        u32                             handle;
  99        struct rsvp_session             *sess;
 100        struct rcu_work                 rwork;
 101};
 102
 103static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid)
 104{
 105        unsigned int h = (__force __u32)dst[RSVP_DST_LEN - 1];
 106
 107        h ^= h>>16;
 108        h ^= h>>8;
 109        return (h ^ protocol ^ tunnelid) & 0xFF;
 110}
 111
 112static inline unsigned int hash_src(__be32 *src)
 113{
 114        unsigned int h = (__force __u32)src[RSVP_DST_LEN-1];
 115
 116        h ^= h>>16;
 117        h ^= h>>8;
 118        h ^= h>>4;
 119        return h & 0xF;
 120}
 121
 122#define RSVP_APPLY_RESULT()                             \
 123{                                                       \
 124        int r = tcf_exts_exec(skb, &f->exts, res);      \
 125        if (r < 0)                                      \
 126                continue;                               \
 127        else if (r > 0)                                 \
 128                return r;                               \
 129}
 130
 131static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 132                         struct tcf_result *res)
 133{
 134        struct rsvp_head *head = rcu_dereference_bh(tp->root);
 135        struct rsvp_session *s;
 136        struct rsvp_filter *f;
 137        unsigned int h1, h2;
 138        __be32 *dst, *src;
 139        u8 protocol;
 140        u8 tunnelid = 0;
 141        u8 *xprt;
 142#if RSVP_DST_LEN == 4
 143        struct ipv6hdr *nhptr;
 144
 145        if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
 146                return -1;
 147        nhptr = ipv6_hdr(skb);
 148#else
 149        struct iphdr *nhptr;
 150
 151        if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
 152                return -1;
 153        nhptr = ip_hdr(skb);
 154#endif
 155restart:
 156
 157#if RSVP_DST_LEN == 4
 158        src = &nhptr->saddr.s6_addr32[0];
 159        dst = &nhptr->daddr.s6_addr32[0];
 160        protocol = nhptr->nexthdr;
 161        xprt = ((u8 *)nhptr) + sizeof(struct ipv6hdr);
 162#else
 163        src = &nhptr->saddr;
 164        dst = &nhptr->daddr;
 165        protocol = nhptr->protocol;
 166        xprt = ((u8 *)nhptr) + (nhptr->ihl<<2);
 167        if (ip_is_fragment(nhptr))
 168                return -1;
 169#endif
 170
 171        h1 = hash_dst(dst, protocol, tunnelid);
 172        h2 = hash_src(src);
 173
 174        for (s = rcu_dereference_bh(head->ht[h1]); s;
 175             s = rcu_dereference_bh(s->next)) {
 176                if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN - 1] &&
 177                    protocol == s->protocol &&
 178                    !(s->dpi.mask &
 179                      (*(u32 *)(xprt + s->dpi.offset) ^ s->dpi.key)) &&
 180#if RSVP_DST_LEN == 4
 181                    dst[0] == s->dst[0] &&
 182                    dst[1] == s->dst[1] &&
 183                    dst[2] == s->dst[2] &&
 184#endif
 185                    tunnelid == s->tunnelid) {
 186
 187                        for (f = rcu_dereference_bh(s->ht[h2]); f;
 188                             f = rcu_dereference_bh(f->next)) {
 189                                if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN - 1] &&
 190                                    !(f->spi.mask & (*(u32 *)(xprt + f->spi.offset) ^ f->spi.key))
 191#if RSVP_DST_LEN == 4
 192                                    &&
 193                                    src[0] == f->src[0] &&
 194                                    src[1] == f->src[1] &&
 195                                    src[2] == f->src[2]
 196#endif
 197                                    ) {
 198                                        *res = f->res;
 199                                        RSVP_APPLY_RESULT();
 200
 201matched:
 202                                        if (f->tunnelhdr == 0)
 203                                                return 0;
 204
 205                                        tunnelid = f->res.classid;
 206                                        nhptr = (void *)(xprt + f->tunnelhdr - sizeof(*nhptr));
 207                                        goto restart;
 208                                }
 209                        }
 210
 211                        /* And wildcard bucket... */
 212                        for (f = rcu_dereference_bh(s->ht[16]); f;
 213                             f = rcu_dereference_bh(f->next)) {
 214                                *res = f->res;
 215                                RSVP_APPLY_RESULT();
 216                                goto matched;
 217                        }
 218                        return -1;
 219                }
 220        }
 221        return -1;
 222}
 223
 224static void rsvp_replace(struct tcf_proto *tp, struct rsvp_filter *n, u32 h)
 225{
 226        struct rsvp_head *head = rtnl_dereference(tp->root);
 227        struct rsvp_session *s;
 228        struct rsvp_filter __rcu **ins;
 229        struct rsvp_filter *pins;
 230        unsigned int h1 = h & 0xFF;
 231        unsigned int h2 = (h >> 8) & 0xFF;
 232
 233        for (s = rtnl_dereference(head->ht[h1]); s;
 234             s = rtnl_dereference(s->next)) {
 235                for (ins = &s->ht[h2], pins = rtnl_dereference(*ins); ;
 236                     ins = &pins->next, pins = rtnl_dereference(*ins)) {
 237                        if (pins->handle == h) {
 238                                RCU_INIT_POINTER(n->next, pins->next);
 239                                rcu_assign_pointer(*ins, n);
 240                                return;
 241                        }
 242                }
 243        }
 244
 245        /* Something went wrong if we are trying to replace a non-existant
 246         * node. Mind as well halt instead of silently failing.
 247         */
 248        BUG_ON(1);
 249}
 250
 251static void *rsvp_get(struct tcf_proto *tp, u32 handle)
 252{
 253        struct rsvp_head *head = rtnl_dereference(tp->root);
 254        struct rsvp_session *s;
 255        struct rsvp_filter *f;
 256        unsigned int h1 = handle & 0xFF;
 257        unsigned int h2 = (handle >> 8) & 0xFF;
 258
 259        if (h2 > 16)
 260                return NULL;
 261
 262        for (s = rtnl_dereference(head->ht[h1]); s;
 263             s = rtnl_dereference(s->next)) {
 264                for (f = rtnl_dereference(s->ht[h2]); f;
 265                     f = rtnl_dereference(f->next)) {
 266                        if (f->handle == handle)
 267                                return f;
 268                }
 269        }
 270        return NULL;
 271}
 272
 273static int rsvp_init(struct tcf_proto *tp)
 274{
 275        struct rsvp_head *data;
 276
 277        data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL);
 278        if (data) {
 279                rcu_assign_pointer(tp->root, data);
 280                return 0;
 281        }
 282        return -ENOBUFS;
 283}
 284
 285static void __rsvp_delete_filter(struct rsvp_filter *f)
 286{
 287        tcf_exts_destroy(&f->exts);
 288        tcf_exts_put_net(&f->exts);
 289        kfree(f);
 290}
 291
 292static void rsvp_delete_filter_work(struct work_struct *work)
 293{
 294        struct rsvp_filter *f = container_of(to_rcu_work(work),
 295                                             struct rsvp_filter,
 296                                             rwork);
 297        rtnl_lock();
 298        __rsvp_delete_filter(f);
 299        rtnl_unlock();
 300}
 301
 302static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
 303{
 304        tcf_unbind_filter(tp, &f->res);
 305        /* all classifiers are required to call tcf_exts_destroy() after rcu
 306         * grace period, since converted-to-rcu actions are relying on that
 307         * in cleanup() callback
 308         */
 309        if (tcf_exts_get_net(&f->exts))
 310                tcf_queue_work(&f->rwork, rsvp_delete_filter_work);
 311        else
 312                __rsvp_delete_filter(f);
 313}
 314
 315static void rsvp_destroy(struct tcf_proto *tp)
 316{
 317        struct rsvp_head *data = rtnl_dereference(tp->root);
 318        int h1, h2;
 319
 320        if (data == NULL)
 321                return;
 322
 323        for (h1 = 0; h1 < 256; h1++) {
 324                struct rsvp_session *s;
 325
 326                while ((s = rtnl_dereference(data->ht[h1])) != NULL) {
 327                        RCU_INIT_POINTER(data->ht[h1], s->next);
 328
 329                        for (h2 = 0; h2 <= 16; h2++) {
 330                                struct rsvp_filter *f;
 331
 332                                while ((f = rtnl_dereference(s->ht[h2])) != NULL) {
 333                                        rcu_assign_pointer(s->ht[h2], f->next);
 334                                        rsvp_delete_filter(tp, f);
 335                                }
 336                        }
 337                        kfree_rcu(s, rcu);
 338                }
 339        }
 340        kfree_rcu(data, rcu);
 341}
 342
 343static int rsvp_delete(struct tcf_proto *tp, void *arg, bool *last)
 344{
 345        struct rsvp_head *head = rtnl_dereference(tp->root);
 346        struct rsvp_filter *nfp, *f = arg;
 347        struct rsvp_filter __rcu **fp;
 348        unsigned int h = f->handle;
 349        struct rsvp_session __rcu **sp;
 350        struct rsvp_session *nsp, *s = f->sess;
 351        int i, h1;
 352
 353        fp = &s->ht[(h >> 8) & 0xFF];
 354        for (nfp = rtnl_dereference(*fp); nfp;
 355             fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
 356                if (nfp == f) {
 357                        RCU_INIT_POINTER(*fp, f->next);
 358                        rsvp_delete_filter(tp, f);
 359
 360                        /* Strip tree */
 361
 362                        for (i = 0; i <= 16; i++)
 363                                if (s->ht[i])
 364                                        goto out;
 365
 366                        /* OK, session has no flows */
 367                        sp = &head->ht[h & 0xFF];
 368                        for (nsp = rtnl_dereference(*sp); nsp;
 369                             sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
 370                                if (nsp == s) {
 371                                        RCU_INIT_POINTER(*sp, s->next);
 372                                        kfree_rcu(s, rcu);
 373                                        goto out;
 374                                }
 375                        }
 376
 377                        break;
 378                }
 379        }
 380
 381out:
 382        *last = true;
 383        for (h1 = 0; h1 < 256; h1++) {
 384                if (rcu_access_pointer(head->ht[h1])) {
 385                        *last = false;
 386                        break;
 387                }
 388        }
 389
 390        return 0;
 391}
 392
 393static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt)
 394{
 395        struct rsvp_head *data = rtnl_dereference(tp->root);
 396        int i = 0xFFFF;
 397
 398        while (i-- > 0) {
 399                u32 h;
 400
 401                if ((data->hgenerator += 0x10000) == 0)
 402                        data->hgenerator = 0x10000;
 403                h = data->hgenerator|salt;
 404                if (!rsvp_get(tp, h))
 405                        return h;
 406        }
 407        return 0;
 408}
 409
 410static int tunnel_bts(struct rsvp_head *data)
 411{
 412        int n = data->tgenerator >> 5;
 413        u32 b = 1 << (data->tgenerator & 0x1F);
 414
 415        if (data->tmap[n] & b)
 416                return 0;
 417        data->tmap[n] |= b;
 418        return 1;
 419}
 420
 421static void tunnel_recycle(struct rsvp_head *data)
 422{
 423        struct rsvp_session __rcu **sht = data->ht;
 424        u32 tmap[256/32];
 425        int h1, h2;
 426
 427        memset(tmap, 0, sizeof(tmap));
 428
 429        for (h1 = 0; h1 < 256; h1++) {
 430                struct rsvp_session *s;
 431                for (s = rtnl_dereference(sht[h1]); s;
 432                     s = rtnl_dereference(s->next)) {
 433                        for (h2 = 0; h2 <= 16; h2++) {
 434                                struct rsvp_filter *f;
 435
 436                                for (f = rtnl_dereference(s->ht[h2]); f;
 437                                     f = rtnl_dereference(f->next)) {
 438                                        if (f->tunnelhdr == 0)
 439                                                continue;
 440                                        data->tgenerator = f->res.classid;
 441                                        tunnel_bts(data);
 442                                }
 443                        }
 444                }
 445        }
 446
 447        memcpy(data->tmap, tmap, sizeof(tmap));
 448}
 449
 450static u32 gen_tunnel(struct rsvp_head *data)
 451{
 452        int i, k;
 453
 454        for (k = 0; k < 2; k++) {
 455                for (i = 255; i > 0; i--) {
 456                        if (++data->tgenerator == 0)
 457                                data->tgenerator = 1;
 458                        if (tunnel_bts(data))
 459                                return data->tgenerator;
 460                }
 461                tunnel_recycle(data);
 462        }
 463        return 0;
 464}
 465
 466static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
 467        [TCA_RSVP_CLASSID]      = { .type = NLA_U32 },
 468        [TCA_RSVP_DST]          = { .type = NLA_BINARY,
 469                                    .len = RSVP_DST_LEN * sizeof(u32) },
 470        [TCA_RSVP_SRC]          = { .type = NLA_BINARY,
 471                                    .len = RSVP_DST_LEN * sizeof(u32) },
 472        [TCA_RSVP_PINFO]        = { .len = sizeof(struct tc_rsvp_pinfo) },
 473};
 474
 475static int rsvp_change(struct net *net, struct sk_buff *in_skb,
 476                       struct tcf_proto *tp, unsigned long base,
 477                       u32 handle,
 478                       struct nlattr **tca,
 479                       void **arg, bool ovr)
 480{
 481        struct rsvp_head *data = rtnl_dereference(tp->root);
 482        struct rsvp_filter *f, *nfp;
 483        struct rsvp_filter __rcu **fp;
 484        struct rsvp_session *nsp, *s;
 485        struct rsvp_session __rcu **sp;
 486        struct tc_rsvp_pinfo *pinfo = NULL;
 487        struct nlattr *opt = tca[TCA_OPTIONS];
 488        struct nlattr *tb[TCA_RSVP_MAX + 1];
 489        struct tcf_exts e;
 490        unsigned int h1, h2;
 491        __be32 *dst;
 492        int err;
 493
 494        if (opt == NULL)
 495                return handle ? -EINVAL : 0;
 496
 497        err = nla_parse_nested(tb, TCA_RSVP_MAX, opt, rsvp_policy);
 498        if (err < 0)
 499                return err;
 500
 501        err = tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE);
 502        if (err < 0)
 503                return err;
 504        err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
 505        if (err < 0)
 506                goto errout2;
 507
 508        f = *arg;
 509        if (f) {
 510                /* Node exists: adjust only classid */
 511                struct rsvp_filter *n;
 512
 513                if (f->handle != handle && handle)
 514                        goto errout2;
 515
 516                n = kmemdup(f, sizeof(*f), GFP_KERNEL);
 517                if (!n) {
 518                        err = -ENOMEM;
 519                        goto errout2;
 520                }
 521
 522                err = tcf_exts_init(&n->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
 523                if (err < 0) {
 524                        kfree(n);
 525                        goto errout2;
 526                }
 527
 528                if (tb[TCA_RSVP_CLASSID]) {
 529                        n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
 530                        tcf_bind_filter(tp, &n->res, base);
 531                }
 532
 533                tcf_exts_change(&n->exts, &e);
 534                rsvp_replace(tp, n, handle);
 535                return 0;
 536        }
 537
 538        /* Now more serious part... */
 539        err = -EINVAL;
 540        if (handle)
 541                goto errout2;
 542        if (tb[TCA_RSVP_DST] == NULL)
 543                goto errout2;
 544
 545        err = -ENOBUFS;
 546        f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL);
 547        if (f == NULL)
 548                goto errout2;
 549
 550        err = tcf_exts_init(&f->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
 551        if (err < 0)
 552                goto errout;
 553        h2 = 16;
 554        if (tb[TCA_RSVP_SRC]) {
 555                memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
 556                h2 = hash_src(f->src);
 557        }
 558        if (tb[TCA_RSVP_PINFO]) {
 559                pinfo = nla_data(tb[TCA_RSVP_PINFO]);
 560                f->spi = pinfo->spi;
 561                f->tunnelhdr = pinfo->tunnelhdr;
 562        }
 563        if (tb[TCA_RSVP_CLASSID])
 564                f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
 565
 566        dst = nla_data(tb[TCA_RSVP_DST]);
 567        h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
 568
 569        err = -ENOMEM;
 570        if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0)
 571                goto errout;
 572
 573        if (f->tunnelhdr) {
 574                err = -EINVAL;
 575                if (f->res.classid > 255)
 576                        goto errout;
 577
 578                err = -ENOMEM;
 579                if (f->res.classid == 0 &&
 580                    (f->res.classid = gen_tunnel(data)) == 0)
 581                        goto errout;
 582        }
 583
 584        for (sp = &data->ht[h1];
 585             (s = rtnl_dereference(*sp)) != NULL;
 586             sp = &s->next) {
 587                if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] &&
 588                    pinfo && pinfo->protocol == s->protocol &&
 589                    memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 &&
 590#if RSVP_DST_LEN == 4
 591                    dst[0] == s->dst[0] &&
 592                    dst[1] == s->dst[1] &&
 593                    dst[2] == s->dst[2] &&
 594#endif
 595                    pinfo->tunnelid == s->tunnelid) {
 596
 597insert:
 598                        /* OK, we found appropriate session */
 599
 600                        fp = &s->ht[h2];
 601
 602                        f->sess = s;
 603                        if (f->tunnelhdr == 0)
 604                                tcf_bind_filter(tp, &f->res, base);
 605
 606                        tcf_exts_change(&f->exts, &e);
 607
 608                        fp = &s->ht[h2];
 609                        for (nfp = rtnl_dereference(*fp); nfp;
 610                             fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
 611                                __u32 mask = nfp->spi.mask & f->spi.mask;
 612
 613                                if (mask != f->spi.mask)
 614                                        break;
 615                        }
 616                        RCU_INIT_POINTER(f->next, nfp);
 617                        rcu_assign_pointer(*fp, f);
 618
 619                        *arg = f;
 620                        return 0;
 621                }
 622        }
 623
 624        /* No session found. Create new one. */
 625
 626        err = -ENOBUFS;
 627        s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL);
 628        if (s == NULL)
 629                goto errout;
 630        memcpy(s->dst, dst, sizeof(s->dst));
 631
 632        if (pinfo) {
 633                s->dpi = pinfo->dpi;
 634                s->protocol = pinfo->protocol;
 635                s->tunnelid = pinfo->tunnelid;
 636        }
 637        sp = &data->ht[h1];
 638        for (nsp = rtnl_dereference(*sp); nsp;
 639             sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
 640                if ((nsp->dpi.mask & s->dpi.mask) != s->dpi.mask)
 641                        break;
 642        }
 643        RCU_INIT_POINTER(s->next, nsp);
 644        rcu_assign_pointer(*sp, s);
 645
 646        goto insert;
 647
 648errout:
 649        tcf_exts_destroy(&f->exts);
 650        kfree(f);
 651errout2:
 652        tcf_exts_destroy(&e);
 653        return err;
 654}
 655
 656static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 657{
 658        struct rsvp_head *head = rtnl_dereference(tp->root);
 659        unsigned int h, h1;
 660
 661        if (arg->stop)
 662                return;
 663
 664        for (h = 0; h < 256; h++) {
 665                struct rsvp_session *s;
 666
 667                for (s = rtnl_dereference(head->ht[h]); s;
 668                     s = rtnl_dereference(s->next)) {
 669                        for (h1 = 0; h1 <= 16; h1++) {
 670                                struct rsvp_filter *f;
 671
 672                                for (f = rtnl_dereference(s->ht[h1]); f;
 673                                     f = rtnl_dereference(f->next)) {
 674                                        if (arg->count < arg->skip) {
 675                                                arg->count++;
 676                                                continue;
 677                                        }
 678                                        if (arg->fn(tp, f, arg) < 0) {
 679                                                arg->stop = 1;
 680                                                return;
 681                                        }
 682                                        arg->count++;
 683                                }
 684                        }
 685                }
 686        }
 687}
 688
 689static int rsvp_dump(struct net *net, struct tcf_proto *tp, void *fh,
 690                     struct sk_buff *skb, struct tcmsg *t)
 691{
 692        struct rsvp_filter *f = fh;
 693        struct rsvp_session *s;
 694        struct nlattr *nest;
 695        struct tc_rsvp_pinfo pinfo;
 696
 697        if (f == NULL)
 698                return skb->len;
 699        s = f->sess;
 700
 701        t->tcm_handle = f->handle;
 702
 703        nest = nla_nest_start(skb, TCA_OPTIONS);
 704        if (nest == NULL)
 705                goto nla_put_failure;
 706
 707        if (nla_put(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst))
 708                goto nla_put_failure;
 709        pinfo.dpi = s->dpi;
 710        pinfo.spi = f->spi;
 711        pinfo.protocol = s->protocol;
 712        pinfo.tunnelid = s->tunnelid;
 713        pinfo.tunnelhdr = f->tunnelhdr;
 714        pinfo.pad = 0;
 715        if (nla_put(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo))
 716                goto nla_put_failure;
 717        if (f->res.classid &&
 718            nla_put_u32(skb, TCA_RSVP_CLASSID, f->res.classid))
 719                goto nla_put_failure;
 720        if (((f->handle >> 8) & 0xFF) != 16 &&
 721            nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src))
 722                goto nla_put_failure;
 723
 724        if (tcf_exts_dump(skb, &f->exts) < 0)
 725                goto nla_put_failure;
 726
 727        nla_nest_end(skb, nest);
 728
 729        if (tcf_exts_dump_stats(skb, &f->exts) < 0)
 730                goto nla_put_failure;
 731        return skb->len;
 732
 733nla_put_failure:
 734        nla_nest_cancel(skb, nest);
 735        return -1;
 736}
 737
 738static void rsvp_bind_class(void *fh, u32 classid, unsigned long cl)
 739{
 740        struct rsvp_filter *f = fh;
 741
 742        if (f && f->res.classid == classid)
 743                f->res.class = cl;
 744}
 745
 746static struct tcf_proto_ops RSVP_OPS __read_mostly = {
 747        .kind           =       RSVP_ID,
 748        .classify       =       rsvp_classify,
 749        .init           =       rsvp_init,
 750        .destroy        =       rsvp_destroy,
 751        .get            =       rsvp_get,
 752        .change         =       rsvp_change,
 753        .delete         =       rsvp_delete,
 754        .walk           =       rsvp_walk,
 755        .dump           =       rsvp_dump,
 756        .bind_class     =       rsvp_bind_class,
 757        .owner          =       THIS_MODULE,
 758};
 759
 760static int __init init_rsvp(void)
 761{
 762        return register_tcf_proto_ops(&RSVP_OPS);
 763}
 764
 765static void __exit exit_rsvp(void)
 766{
 767        unregister_tcf_proto_ops(&RSVP_OPS);
 768}
 769
 770module_init(init_rsvp)
 771module_exit(exit_rsvp)
 772