Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003  * net/sched/cls_rsvp.h Template file for RSVPv[46] classifiers.
0004  *
0005  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
0006  */
0007 
0008 /*
0009    Comparing to general packet classification problem,
0010    RSVP needs only several relatively simple rules:
0011 
0012    * (dst, protocol) are always specified,
0013      so that we are able to hash them.
0014    * src may be exact, or may be wildcard, so that
0015      we can keep a hash table plus one wildcard entry.
0016    * source port (or flow label) is important only if src is given.
0017 
0018    IMPLEMENTATION.
0019 
0020    We use a two level hash table: The top level is keyed by
0021    destination address and protocol ID, every bucket contains a list
0022    of "rsvp sessions", identified by destination address, protocol and
0023    DPI(="Destination Port ID"): triple (key, mask, offset).
0024 
0025    Every bucket has a smaller hash table keyed by source address
0026    (cf. RSVP flowspec) and one wildcard entry for wildcard reservations.
0027    Every bucket is again a list of "RSVP flows", selected by
0028    source address and SPI(="Source Port ID" here rather than
0029    "security parameter index"): triple (key, mask, offset).
0030 
0031 
0032    NOTE 1. All the packets with IPv6 extension headers (but AH and ESP)
0033    and all fragmented packets go to the best-effort traffic class.
0034 
0035 
0036    NOTE 2. Two "port id"'s seems to be redundant, rfc2207 requires
0037    only one "Generalized Port Identifier". So that for classic
0038    ah, esp (and udp,tcp) both *pi should coincide or one of them
0039    should be wildcard.
0040 
0041    At first sight, this redundancy is just a waste of CPU
0042    resources. But DPI and SPI add the possibility to assign different
0043    priorities to GPIs. Look also at note 4 about tunnels below.
0044 
0045 
0046    NOTE 3. One complication is the case of tunneled packets.
0047    We implement it as following: if the first lookup
0048    matches a special session with "tunnelhdr" value not zero,
0049    flowid doesn't contain the true flow ID, but the tunnel ID (1...255).
0050    In this case, we pull tunnelhdr bytes and restart lookup
0051    with tunnel ID added to the list of keys. Simple and stupid 8)8)
0052    It's enough for PIMREG and IPIP.
0053 
0054 
0055    NOTE 4. Two GPIs make it possible to parse even GRE packets.
0056    F.e. DPI can select ETH_P_IP (and necessary flags to make
0057    tunnelhdr correct) in GRE protocol field and SPI matches
0058    GRE key. Is it not nice? 8)8)
0059 
0060 
0061    Well, as result, despite its simplicity, we get a pretty
0062    powerful classification engine.  */
0063 
0064 
0065 struct rsvp_head {
0066     u32         tmap[256/32];
0067     u32         hgenerator;
0068     u8          tgenerator;
0069     struct rsvp_session __rcu *ht[256];
0070     struct rcu_head     rcu;
0071 };
0072 
0073 struct rsvp_session {
0074     struct rsvp_session __rcu   *next;
0075     __be32              dst[RSVP_DST_LEN];
0076     struct tc_rsvp_gpi      dpi;
0077     u8              protocol;
0078     u8              tunnelid;
0079     /* 16 (src,sport) hash slots, and one wildcard source slot */
0080     struct rsvp_filter __rcu    *ht[16 + 1];
0081     struct rcu_head         rcu;
0082 };
0083 
0084 
0085 struct rsvp_filter {
0086     struct rsvp_filter __rcu    *next;
0087     __be32              src[RSVP_DST_LEN];
0088     struct tc_rsvp_gpi      spi;
0089     u8              tunnelhdr;
0090 
0091     struct tcf_result       res;
0092     struct tcf_exts         exts;
0093 
0094     u32             handle;
0095     struct rsvp_session     *sess;
0096     struct rcu_work         rwork;
0097 };
0098 
0099 static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid)
0100 {
0101     unsigned int h = (__force __u32)dst[RSVP_DST_LEN - 1];
0102 
0103     h ^= h>>16;
0104     h ^= h>>8;
0105     return (h ^ protocol ^ tunnelid) & 0xFF;
0106 }
0107 
0108 static inline unsigned int hash_src(__be32 *src)
0109 {
0110     unsigned int h = (__force __u32)src[RSVP_DST_LEN-1];
0111 
0112     h ^= h>>16;
0113     h ^= h>>8;
0114     h ^= h>>4;
0115     return h & 0xF;
0116 }
0117 
0118 #define RSVP_APPLY_RESULT()             \
0119 {                           \
0120     int r = tcf_exts_exec(skb, &f->exts, res);  \
0121     if (r < 0)                  \
0122         continue;               \
0123     else if (r > 0)                 \
0124         return r;               \
0125 }
0126 
0127 static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp,
0128              struct tcf_result *res)
0129 {
0130     struct rsvp_head *head = rcu_dereference_bh(tp->root);
0131     struct rsvp_session *s;
0132     struct rsvp_filter *f;
0133     unsigned int h1, h2;
0134     __be32 *dst, *src;
0135     u8 protocol;
0136     u8 tunnelid = 0;
0137     u8 *xprt;
0138 #if RSVP_DST_LEN == 4
0139     struct ipv6hdr *nhptr;
0140 
0141     if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
0142         return -1;
0143     nhptr = ipv6_hdr(skb);
0144 #else
0145     struct iphdr *nhptr;
0146 
0147     if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
0148         return -1;
0149     nhptr = ip_hdr(skb);
0150 #endif
0151 restart:
0152 
0153 #if RSVP_DST_LEN == 4
0154     src = &nhptr->saddr.s6_addr32[0];
0155     dst = &nhptr->daddr.s6_addr32[0];
0156     protocol = nhptr->nexthdr;
0157     xprt = ((u8 *)nhptr) + sizeof(struct ipv6hdr);
0158 #else
0159     src = &nhptr->saddr;
0160     dst = &nhptr->daddr;
0161     protocol = nhptr->protocol;
0162     xprt = ((u8 *)nhptr) + (nhptr->ihl<<2);
0163     if (ip_is_fragment(nhptr))
0164         return -1;
0165 #endif
0166 
0167     h1 = hash_dst(dst, protocol, tunnelid);
0168     h2 = hash_src(src);
0169 
0170     for (s = rcu_dereference_bh(head->ht[h1]); s;
0171          s = rcu_dereference_bh(s->next)) {
0172         if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN - 1] &&
0173             protocol == s->protocol &&
0174             !(s->dpi.mask &
0175               (*(u32 *)(xprt + s->dpi.offset) ^ s->dpi.key)) &&
0176 #if RSVP_DST_LEN == 4
0177             dst[0] == s->dst[0] &&
0178             dst[1] == s->dst[1] &&
0179             dst[2] == s->dst[2] &&
0180 #endif
0181             tunnelid == s->tunnelid) {
0182 
0183             for (f = rcu_dereference_bh(s->ht[h2]); f;
0184                  f = rcu_dereference_bh(f->next)) {
0185                 if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN - 1] &&
0186                     !(f->spi.mask & (*(u32 *)(xprt + f->spi.offset) ^ f->spi.key))
0187 #if RSVP_DST_LEN == 4
0188                     &&
0189                     src[0] == f->src[0] &&
0190                     src[1] == f->src[1] &&
0191                     src[2] == f->src[2]
0192 #endif
0193                     ) {
0194                     *res = f->res;
0195                     RSVP_APPLY_RESULT();
0196 
0197 matched:
0198                     if (f->tunnelhdr == 0)
0199                         return 0;
0200 
0201                     tunnelid = f->res.classid;
0202                     nhptr = (void *)(xprt + f->tunnelhdr - sizeof(*nhptr));
0203                     goto restart;
0204                 }
0205             }
0206 
0207             /* And wildcard bucket... */
0208             for (f = rcu_dereference_bh(s->ht[16]); f;
0209                  f = rcu_dereference_bh(f->next)) {
0210                 *res = f->res;
0211                 RSVP_APPLY_RESULT();
0212                 goto matched;
0213             }
0214             return -1;
0215         }
0216     }
0217     return -1;
0218 }
0219 
0220 static void rsvp_replace(struct tcf_proto *tp, struct rsvp_filter *n, u32 h)
0221 {
0222     struct rsvp_head *head = rtnl_dereference(tp->root);
0223     struct rsvp_session *s;
0224     struct rsvp_filter __rcu **ins;
0225     struct rsvp_filter *pins;
0226     unsigned int h1 = h & 0xFF;
0227     unsigned int h2 = (h >> 8) & 0xFF;
0228 
0229     for (s = rtnl_dereference(head->ht[h1]); s;
0230          s = rtnl_dereference(s->next)) {
0231         for (ins = &s->ht[h2], pins = rtnl_dereference(*ins); ;
0232              ins = &pins->next, pins = rtnl_dereference(*ins)) {
0233             if (pins->handle == h) {
0234                 RCU_INIT_POINTER(n->next, pins->next);
0235                 rcu_assign_pointer(*ins, n);
0236                 return;
0237             }
0238         }
0239     }
0240 
0241     /* Something went wrong if we are trying to replace a non-existent
0242      * node. Mind as well halt instead of silently failing.
0243      */
0244     BUG_ON(1);
0245 }
0246 
0247 static void *rsvp_get(struct tcf_proto *tp, u32 handle)
0248 {
0249     struct rsvp_head *head = rtnl_dereference(tp->root);
0250     struct rsvp_session *s;
0251     struct rsvp_filter *f;
0252     unsigned int h1 = handle & 0xFF;
0253     unsigned int h2 = (handle >> 8) & 0xFF;
0254 
0255     if (h2 > 16)
0256         return NULL;
0257 
0258     for (s = rtnl_dereference(head->ht[h1]); s;
0259          s = rtnl_dereference(s->next)) {
0260         for (f = rtnl_dereference(s->ht[h2]); f;
0261              f = rtnl_dereference(f->next)) {
0262             if (f->handle == handle)
0263                 return f;
0264         }
0265     }
0266     return NULL;
0267 }
0268 
0269 static int rsvp_init(struct tcf_proto *tp)
0270 {
0271     struct rsvp_head *data;
0272 
0273     data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL);
0274     if (data) {
0275         rcu_assign_pointer(tp->root, data);
0276         return 0;
0277     }
0278     return -ENOBUFS;
0279 }
0280 
0281 static void __rsvp_delete_filter(struct rsvp_filter *f)
0282 {
0283     tcf_exts_destroy(&f->exts);
0284     tcf_exts_put_net(&f->exts);
0285     kfree(f);
0286 }
0287 
0288 static void rsvp_delete_filter_work(struct work_struct *work)
0289 {
0290     struct rsvp_filter *f = container_of(to_rcu_work(work),
0291                          struct rsvp_filter,
0292                          rwork);
0293     rtnl_lock();
0294     __rsvp_delete_filter(f);
0295     rtnl_unlock();
0296 }
0297 
0298 static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
0299 {
0300     tcf_unbind_filter(tp, &f->res);
0301     /* all classifiers are required to call tcf_exts_destroy() after rcu
0302      * grace period, since converted-to-rcu actions are relying on that
0303      * in cleanup() callback
0304      */
0305     if (tcf_exts_get_net(&f->exts))
0306         tcf_queue_work(&f->rwork, rsvp_delete_filter_work);
0307     else
0308         __rsvp_delete_filter(f);
0309 }
0310 
0311 static void rsvp_destroy(struct tcf_proto *tp, bool rtnl_held,
0312              struct netlink_ext_ack *extack)
0313 {
0314     struct rsvp_head *data = rtnl_dereference(tp->root);
0315     int h1, h2;
0316 
0317     if (data == NULL)
0318         return;
0319 
0320     for (h1 = 0; h1 < 256; h1++) {
0321         struct rsvp_session *s;
0322 
0323         while ((s = rtnl_dereference(data->ht[h1])) != NULL) {
0324             RCU_INIT_POINTER(data->ht[h1], s->next);
0325 
0326             for (h2 = 0; h2 <= 16; h2++) {
0327                 struct rsvp_filter *f;
0328 
0329                 while ((f = rtnl_dereference(s->ht[h2])) != NULL) {
0330                     rcu_assign_pointer(s->ht[h2], f->next);
0331                     rsvp_delete_filter(tp, f);
0332                 }
0333             }
0334             kfree_rcu(s, rcu);
0335         }
0336     }
0337     kfree_rcu(data, rcu);
0338 }
0339 
0340 static int rsvp_delete(struct tcf_proto *tp, void *arg, bool *last,
0341                bool rtnl_held, struct netlink_ext_ack *extack)
0342 {
0343     struct rsvp_head *head = rtnl_dereference(tp->root);
0344     struct rsvp_filter *nfp, *f = arg;
0345     struct rsvp_filter __rcu **fp;
0346     unsigned int h = f->handle;
0347     struct rsvp_session __rcu **sp;
0348     struct rsvp_session *nsp, *s = f->sess;
0349     int i, h1;
0350 
0351     fp = &s->ht[(h >> 8) & 0xFF];
0352     for (nfp = rtnl_dereference(*fp); nfp;
0353          fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
0354         if (nfp == f) {
0355             RCU_INIT_POINTER(*fp, f->next);
0356             rsvp_delete_filter(tp, f);
0357 
0358             /* Strip tree */
0359 
0360             for (i = 0; i <= 16; i++)
0361                 if (s->ht[i])
0362                     goto out;
0363 
0364             /* OK, session has no flows */
0365             sp = &head->ht[h & 0xFF];
0366             for (nsp = rtnl_dereference(*sp); nsp;
0367                  sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
0368                 if (nsp == s) {
0369                     RCU_INIT_POINTER(*sp, s->next);
0370                     kfree_rcu(s, rcu);
0371                     goto out;
0372                 }
0373             }
0374 
0375             break;
0376         }
0377     }
0378 
0379 out:
0380     *last = true;
0381     for (h1 = 0; h1 < 256; h1++) {
0382         if (rcu_access_pointer(head->ht[h1])) {
0383             *last = false;
0384             break;
0385         }
0386     }
0387 
0388     return 0;
0389 }
0390 
0391 static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt)
0392 {
0393     struct rsvp_head *data = rtnl_dereference(tp->root);
0394     int i = 0xFFFF;
0395 
0396     while (i-- > 0) {
0397         u32 h;
0398 
0399         if ((data->hgenerator += 0x10000) == 0)
0400             data->hgenerator = 0x10000;
0401         h = data->hgenerator|salt;
0402         if (!rsvp_get(tp, h))
0403             return h;
0404     }
0405     return 0;
0406 }
0407 
0408 static int tunnel_bts(struct rsvp_head *data)
0409 {
0410     int n = data->tgenerator >> 5;
0411     u32 b = 1 << (data->tgenerator & 0x1F);
0412 
0413     if (data->tmap[n] & b)
0414         return 0;
0415     data->tmap[n] |= b;
0416     return 1;
0417 }
0418 
0419 static void tunnel_recycle(struct rsvp_head *data)
0420 {
0421     struct rsvp_session __rcu **sht = data->ht;
0422     u32 tmap[256/32];
0423     int h1, h2;
0424 
0425     memset(tmap, 0, sizeof(tmap));
0426 
0427     for (h1 = 0; h1 < 256; h1++) {
0428         struct rsvp_session *s;
0429         for (s = rtnl_dereference(sht[h1]); s;
0430              s = rtnl_dereference(s->next)) {
0431             for (h2 = 0; h2 <= 16; h2++) {
0432                 struct rsvp_filter *f;
0433 
0434                 for (f = rtnl_dereference(s->ht[h2]); f;
0435                      f = rtnl_dereference(f->next)) {
0436                     if (f->tunnelhdr == 0)
0437                         continue;
0438                     data->tgenerator = f->res.classid;
0439                     tunnel_bts(data);
0440                 }
0441             }
0442         }
0443     }
0444 
0445     memcpy(data->tmap, tmap, sizeof(tmap));
0446 }
0447 
0448 static u32 gen_tunnel(struct rsvp_head *data)
0449 {
0450     int i, k;
0451 
0452     for (k = 0; k < 2; k++) {
0453         for (i = 255; i > 0; i--) {
0454             if (++data->tgenerator == 0)
0455                 data->tgenerator = 1;
0456             if (tunnel_bts(data))
0457                 return data->tgenerator;
0458         }
0459         tunnel_recycle(data);
0460     }
0461     return 0;
0462 }
0463 
0464 static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
0465     [TCA_RSVP_CLASSID]  = { .type = NLA_U32 },
0466     [TCA_RSVP_DST]      = { .len = RSVP_DST_LEN * sizeof(u32) },
0467     [TCA_RSVP_SRC]      = { .len = RSVP_DST_LEN * sizeof(u32) },
0468     [TCA_RSVP_PINFO]    = { .len = sizeof(struct tc_rsvp_pinfo) },
0469 };
0470 
0471 static int rsvp_change(struct net *net, struct sk_buff *in_skb,
0472                struct tcf_proto *tp, unsigned long base,
0473                u32 handle, struct nlattr **tca,
0474                void **arg, u32 flags,
0475                struct netlink_ext_ack *extack)
0476 {
0477     struct rsvp_head *data = rtnl_dereference(tp->root);
0478     struct rsvp_filter *f, *nfp;
0479     struct rsvp_filter __rcu **fp;
0480     struct rsvp_session *nsp, *s;
0481     struct rsvp_session __rcu **sp;
0482     struct tc_rsvp_pinfo *pinfo = NULL;
0483     struct nlattr *opt = tca[TCA_OPTIONS];
0484     struct nlattr *tb[TCA_RSVP_MAX + 1];
0485     struct tcf_exts e;
0486     unsigned int h1, h2;
0487     __be32 *dst;
0488     int err;
0489 
0490     if (opt == NULL)
0491         return handle ? -EINVAL : 0;
0492 
0493     err = nla_parse_nested_deprecated(tb, TCA_RSVP_MAX, opt, rsvp_policy,
0494                       NULL);
0495     if (err < 0)
0496         return err;
0497 
0498     err = tcf_exts_init(&e, net, TCA_RSVP_ACT, TCA_RSVP_POLICE);
0499     if (err < 0)
0500         return err;
0501     err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, flags,
0502                 extack);
0503     if (err < 0)
0504         goto errout2;
0505 
0506     f = *arg;
0507     if (f) {
0508         /* Node exists: adjust only classid */
0509         struct rsvp_filter *n;
0510 
0511         if (f->handle != handle && handle)
0512             goto errout2;
0513 
0514         n = kmemdup(f, sizeof(*f), GFP_KERNEL);
0515         if (!n) {
0516             err = -ENOMEM;
0517             goto errout2;
0518         }
0519 
0520         err = tcf_exts_init(&n->exts, net, TCA_RSVP_ACT,
0521                     TCA_RSVP_POLICE);
0522         if (err < 0) {
0523             kfree(n);
0524             goto errout2;
0525         }
0526 
0527         if (tb[TCA_RSVP_CLASSID]) {
0528             n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
0529             tcf_bind_filter(tp, &n->res, base);
0530         }
0531 
0532         tcf_exts_change(&n->exts, &e);
0533         rsvp_replace(tp, n, handle);
0534         return 0;
0535     }
0536 
0537     /* Now more serious part... */
0538     err = -EINVAL;
0539     if (handle)
0540         goto errout2;
0541     if (tb[TCA_RSVP_DST] == NULL)
0542         goto errout2;
0543 
0544     err = -ENOBUFS;
0545     f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL);
0546     if (f == NULL)
0547         goto errout2;
0548 
0549     err = tcf_exts_init(&f->exts, net, TCA_RSVP_ACT, TCA_RSVP_POLICE);
0550     if (err < 0)
0551         goto errout;
0552     h2 = 16;
0553     if (tb[TCA_RSVP_SRC]) {
0554         memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
0555         h2 = hash_src(f->src);
0556     }
0557     if (tb[TCA_RSVP_PINFO]) {
0558         pinfo = nla_data(tb[TCA_RSVP_PINFO]);
0559         f->spi = pinfo->spi;
0560         f->tunnelhdr = pinfo->tunnelhdr;
0561     }
0562     if (tb[TCA_RSVP_CLASSID])
0563         f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
0564 
0565     dst = nla_data(tb[TCA_RSVP_DST]);
0566     h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
0567 
0568     err = -ENOMEM;
0569     if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0)
0570         goto errout;
0571 
0572     if (f->tunnelhdr) {
0573         err = -EINVAL;
0574         if (f->res.classid > 255)
0575             goto errout;
0576 
0577         err = -ENOMEM;
0578         if (f->res.classid == 0 &&
0579             (f->res.classid = gen_tunnel(data)) == 0)
0580             goto errout;
0581     }
0582 
0583     for (sp = &data->ht[h1];
0584          (s = rtnl_dereference(*sp)) != NULL;
0585          sp = &s->next) {
0586         if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] &&
0587             pinfo && pinfo->protocol == s->protocol &&
0588             memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 &&
0589 #if RSVP_DST_LEN == 4
0590             dst[0] == s->dst[0] &&
0591             dst[1] == s->dst[1] &&
0592             dst[2] == s->dst[2] &&
0593 #endif
0594             pinfo->tunnelid == s->tunnelid) {
0595 
0596 insert:
0597             /* OK, we found appropriate session */
0598 
0599             fp = &s->ht[h2];
0600 
0601             f->sess = s;
0602             if (f->tunnelhdr == 0)
0603                 tcf_bind_filter(tp, &f->res, base);
0604 
0605             tcf_exts_change(&f->exts, &e);
0606 
0607             fp = &s->ht[h2];
0608             for (nfp = rtnl_dereference(*fp); nfp;
0609                  fp = &nfp->next, nfp = rtnl_dereference(*fp)) {
0610                 __u32 mask = nfp->spi.mask & f->spi.mask;
0611 
0612                 if (mask != f->spi.mask)
0613                     break;
0614             }
0615             RCU_INIT_POINTER(f->next, nfp);
0616             rcu_assign_pointer(*fp, f);
0617 
0618             *arg = f;
0619             return 0;
0620         }
0621     }
0622 
0623     /* No session found. Create new one. */
0624 
0625     err = -ENOBUFS;
0626     s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL);
0627     if (s == NULL)
0628         goto errout;
0629     memcpy(s->dst, dst, sizeof(s->dst));
0630 
0631     if (pinfo) {
0632         s->dpi = pinfo->dpi;
0633         s->protocol = pinfo->protocol;
0634         s->tunnelid = pinfo->tunnelid;
0635     }
0636     sp = &data->ht[h1];
0637     for (nsp = rtnl_dereference(*sp); nsp;
0638          sp = &nsp->next, nsp = rtnl_dereference(*sp)) {
0639         if ((nsp->dpi.mask & s->dpi.mask) != s->dpi.mask)
0640             break;
0641     }
0642     RCU_INIT_POINTER(s->next, nsp);
0643     rcu_assign_pointer(*sp, s);
0644 
0645     goto insert;
0646 
0647 errout:
0648     tcf_exts_destroy(&f->exts);
0649     kfree(f);
0650 errout2:
0651     tcf_exts_destroy(&e);
0652     return err;
0653 }
0654 
0655 static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg,
0656               bool rtnl_held)
0657 {
0658     struct rsvp_head *head = rtnl_dereference(tp->root);
0659     unsigned int h, h1;
0660 
0661     if (arg->stop)
0662         return;
0663 
0664     for (h = 0; h < 256; h++) {
0665         struct rsvp_session *s;
0666 
0667         for (s = rtnl_dereference(head->ht[h]); s;
0668              s = rtnl_dereference(s->next)) {
0669             for (h1 = 0; h1 <= 16; h1++) {
0670                 struct rsvp_filter *f;
0671 
0672                 for (f = rtnl_dereference(s->ht[h1]); f;
0673                      f = rtnl_dereference(f->next)) {
0674                     if (arg->count < arg->skip) {
0675                         arg->count++;
0676                         continue;
0677                     }
0678                     if (arg->fn(tp, f, arg) < 0) {
0679                         arg->stop = 1;
0680                         return;
0681                     }
0682                     arg->count++;
0683                 }
0684             }
0685         }
0686     }
0687 }
0688 
0689 static int rsvp_dump(struct net *net, struct tcf_proto *tp, void *fh,
0690              struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
0691 {
0692     struct rsvp_filter *f = fh;
0693     struct rsvp_session *s;
0694     struct nlattr *nest;
0695     struct tc_rsvp_pinfo pinfo;
0696 
0697     if (f == NULL)
0698         return skb->len;
0699     s = f->sess;
0700 
0701     t->tcm_handle = f->handle;
0702 
0703     nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
0704     if (nest == NULL)
0705         goto nla_put_failure;
0706 
0707     if (nla_put(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst))
0708         goto nla_put_failure;
0709     pinfo.dpi = s->dpi;
0710     pinfo.spi = f->spi;
0711     pinfo.protocol = s->protocol;
0712     pinfo.tunnelid = s->tunnelid;
0713     pinfo.tunnelhdr = f->tunnelhdr;
0714     pinfo.pad = 0;
0715     if (nla_put(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo))
0716         goto nla_put_failure;
0717     if (f->res.classid &&
0718         nla_put_u32(skb, TCA_RSVP_CLASSID, f->res.classid))
0719         goto nla_put_failure;
0720     if (((f->handle >> 8) & 0xFF) != 16 &&
0721         nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src))
0722         goto nla_put_failure;
0723 
0724     if (tcf_exts_dump(skb, &f->exts) < 0)
0725         goto nla_put_failure;
0726 
0727     nla_nest_end(skb, nest);
0728 
0729     if (tcf_exts_dump_stats(skb, &f->exts) < 0)
0730         goto nla_put_failure;
0731     return skb->len;
0732 
0733 nla_put_failure:
0734     nla_nest_cancel(skb, nest);
0735     return -1;
0736 }
0737 
0738 static void rsvp_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
0739                 unsigned long base)
0740 {
0741     struct rsvp_filter *f = fh;
0742 
0743     if (f && f->res.classid == classid) {
0744         if (cl)
0745             __tcf_bind_filter(q, &f->res, base);
0746         else
0747             __tcf_unbind_filter(q, &f->res);
0748     }
0749 }
0750 
0751 static struct tcf_proto_ops RSVP_OPS __read_mostly = {
0752     .kind       =   RSVP_ID,
0753     .classify   =   rsvp_classify,
0754     .init       =   rsvp_init,
0755     .destroy    =   rsvp_destroy,
0756     .get        =   rsvp_get,
0757     .change     =   rsvp_change,
0758     .delete     =   rsvp_delete,
0759     .walk       =   rsvp_walk,
0760     .dump       =   rsvp_dump,
0761     .bind_class =   rsvp_bind_class,
0762     .owner      =   THIS_MODULE,
0763 };
0764 
0765 static int __init init_rsvp(void)
0766 {
0767     return register_tcf_proto_ops(&RSVP_OPS);
0768 }
0769 
0770 static void __exit exit_rsvp(void)
0771 {
0772     unregister_tcf_proto_ops(&RSVP_OPS);
0773 }
0774 
0775 module_init(init_rsvp)
0776 module_exit(exit_rsvp)