string: factorize skip_spaces and export it to be generally available
[safe/jmp/linux-2.6] / net / sched / em_meta.c
index cf68a59..24dce8b 100644 (file)
@@ -9,7 +9,7 @@
  * Authors:    Thomas Graf <tgraf@suug.ch>
  *
  * ==========================================================================
- * 
+ *
  *     The metadata ematch compares two meta objects where each object
  *     represents either a meta value stored in the kernel or a static
  *     value provided by userspace. The objects are not provided by
  *     ppp0..9.
  *
  *     NOTE: Certain meta values depend on other subsystems and are
- *           only available if that subsytem is enabled in the kernel.
+ *           only available if that subsystem is enabled in the kernel.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -66,6 +65,7 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/random.h>
+#include <linux/if_vlan.h>
 #include <linux/tc_ematch/tc_em_meta.h>
 #include <net/dst.h>
 #include <net/route.h>
@@ -171,6 +171,23 @@ META_COLLECTOR(var_dev)
 }
 
 /**************************************************************************
+ * vlan tag
+ **************************************************************************/
+
+META_COLLECTOR(int_vlan_tag)
+{
+       unsigned short tag;
+
+       tag = vlan_tx_tag_get(skb);
+       if (!tag && __vlan_get_tag(skb, &tag))
+               *err = -1;
+       else
+               dst->value = tag;
+}
+
+
+
+/**************************************************************************
  * skb attributes
  **************************************************************************/
 
@@ -209,13 +226,9 @@ META_COLLECTOR(int_maclen)
  * Netfilter
  **************************************************************************/
 
-META_COLLECTOR(int_nfmark)
+META_COLLECTOR(int_mark)
 {
-#ifdef CONFIG_NETFILTER
-       dst->value = skb->nfmark;
-#else
-       dst->value = 0;
-#endif
+       dst->value = skb->mark;
 }
 
 /**************************************************************************
@@ -233,11 +246,11 @@ META_COLLECTOR(int_tcindex)
 
 META_COLLECTOR(int_rtclassid)
 {
-       if (unlikely(skb->dst == NULL))
+       if (unlikely(skb_dst(skb) == NULL))
                *err = -1;
        else
 #ifdef CONFIG_NET_CLS_ROUTE
-               dst->value = skb->dst->tclassid;
+               dst->value = skb_dst(skb)->tclassid;
 #else
                dst->value = 0;
 #endif
@@ -245,10 +258,10 @@ META_COLLECTOR(int_rtclassid)
 
 META_COLLECTOR(int_rtiif)
 {
-       if (unlikely(skb->dst == NULL))
+       if (unlikely(skb_rtable(skb) == NULL))
                *err = -1;
        else
-               dst->value = ((struct rtable*) skb->dst)->fl.iif;
+               dst->value = skb_rtable(skb)->fl.iif;
 }
 
 /**************************************************************************
@@ -290,17 +303,18 @@ META_COLLECTOR(var_sk_bound_if)
 {
        SKIP_NONLOCAL(skb);
 
-        if (skb->sk->sk_bound_dev_if == 0) {
+       if (skb->sk->sk_bound_dev_if == 0) {
                dst->value = (unsigned long) "any";
                dst->len = 3;
-        } else  {
+       } else {
                struct net_device *dev;
-               
-               dev = dev_get_by_index(skb->sk->sk_bound_dev_if);
+
+               rcu_read_lock();
+               dev = dev_get_by_index_rcu(sock_net(skb->sk),
+                                          skb->sk->sk_bound_dev_if);
                *err = var_dev(dev, dst);
-               if (dev)
-                       dev_put(dev);
-        }
+               rcu_read_unlock();
+       }
 }
 
 META_COLLECTOR(int_sk_refcnt)
@@ -336,13 +350,13 @@ META_COLLECTOR(int_sk_type)
 META_COLLECTOR(int_sk_rmem_alloc)
 {
        SKIP_NONLOCAL(skb);
-       dst->value = atomic_read(&skb->sk->sk_rmem_alloc);
+       dst->value = sk_rmem_alloc_get(skb->sk);
 }
 
 META_COLLECTOR(int_sk_wmem_alloc)
 {
        SKIP_NONLOCAL(skb);
-       dst->value = atomic_read(&skb->sk->sk_wmem_alloc);
+       dst->value = sk_wmem_alloc_get(skb->sk);
 }
 
 META_COLLECTOR(int_sk_omem_alloc)
@@ -491,7 +505,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
                [META_ID(PKTLEN)]               = META_FUNC(int_pktlen),
                [META_ID(DATALEN)]              = META_FUNC(int_datalen),
                [META_ID(MACLEN)]               = META_FUNC(int_maclen),
-               [META_ID(NFMARK)]               = META_FUNC(int_nfmark),
+               [META_ID(NFMARK)]               = META_FUNC(int_mark),
                [META_ID(TCINDEX)]              = META_FUNC(int_tcindex),
                [META_ID(RTCLASSID)]            = META_FUNC(int_rtclassid),
                [META_ID(RTIIF)]                = META_FUNC(int_rtiif),
@@ -525,6 +539,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
                [META_ID(SK_SNDTIMEO)]          = META_FUNC(int_sk_sndtimeo),
                [META_ID(SK_SENDMSG_OFF)]       = META_FUNC(int_sk_sendmsg_off),
                [META_ID(SK_WRITE_PENDING)]     = META_FUNC(int_sk_write_pend),
+               [META_ID(VLAN_TAG)]             = META_FUNC(int_vlan_tag),
        }
 };
 
@@ -547,22 +562,20 @@ static int meta_var_compare(struct meta_obj *a, struct meta_obj *b)
        return r;
 }
 
-static int meta_var_change(struct meta_value *dst, struct rtattr *rta)
+static int meta_var_change(struct meta_value *dst, struct nlattr *nla)
 {
-       int len = RTA_PAYLOAD(rta);
+       int len = nla_len(nla);
 
-       dst->val = (unsigned long) kmalloc(len, GFP_KERNEL);
+       dst->val = (unsigned long)kmemdup(nla_data(nla), len, GFP_KERNEL);
        if (dst->val == 0UL)
                return -ENOMEM;
-       memcpy((void *) dst->val, RTA_DATA(rta), len);
        dst->len = len;
        return 0;
 }
 
 static void meta_var_destroy(struct meta_value *v)
 {
-       if (v->val)
-               kfree((void *) v->val);
+       kfree((void *) v->val);
 }
 
 static void meta_var_apply_extras(struct meta_value *v,
@@ -577,10 +590,10 @@ static void meta_var_apply_extras(struct meta_value *v,
 static int meta_var_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
 {
        if (v->val && v->len)
-               RTA_PUT(skb, tlv, v->len, (void *) v->val);
+               NLA_PUT(skb, tlv, v->len, (void *) v->val);
        return 0;
 
-rtattr_failure:
+nla_put_failure:
        return -1;
 }
 
@@ -601,13 +614,13 @@ static int meta_int_compare(struct meta_obj *a, struct meta_obj *b)
                return 1;
 }
 
-static int meta_int_change(struct meta_value *dst, struct rtattr *rta)
+static int meta_int_change(struct meta_value *dst, struct nlattr *nla)
 {
-       if (RTA_PAYLOAD(rta) >= sizeof(unsigned long)) {
-               dst->val = *(unsigned long *) RTA_DATA(rta);
+       if (nla_len(nla) >= sizeof(unsigned long)) {
+               dst->val = *(unsigned long *) nla_data(nla);
                dst->len = sizeof(unsigned long);
-       } else if (RTA_PAYLOAD(rta) == sizeof(u32)) {
-               dst->val = *(u32 *) RTA_DATA(rta);
+       } else if (nla_len(nla) == sizeof(u32)) {
+               dst->val = nla_get_u32(nla);
                dst->len = sizeof(u32);
        } else
                return -EINVAL;
@@ -628,15 +641,14 @@ static void meta_int_apply_extras(struct meta_value *v,
 static int meta_int_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
 {
        if (v->len == sizeof(unsigned long))
-               RTA_PUT(skb, tlv, sizeof(unsigned long), &v->val);
+               NLA_PUT(skb, tlv, sizeof(unsigned long), &v->val);
        else if (v->len == sizeof(u32)) {
-               u32 d = v->val;
-               RTA_PUT(skb, tlv, sizeof(d), &d);
+               NLA_PUT_U32(skb, tlv, v->val);
        }
 
        return 0;
 
-rtattr_failure:
+nla_put_failure:
        return -1;
 }
 
@@ -648,7 +660,7 @@ struct meta_type_ops
 {
        void    (*destroy)(struct meta_value *);
        int     (*compare)(struct meta_obj *, struct meta_obj *);
-       int     (*change)(struct meta_value *, struct rtattr *);
+       int     (*change)(struct meta_value *, struct nlattr *);
        void    (*apply_extras)(struct meta_value *, struct meta_obj *);
        int     (*dump)(struct sk_buff *, struct meta_value *, int);
 };
@@ -678,8 +690,8 @@ static inline struct meta_type_ops * meta_type_ops(struct meta_value *v)
  * Core
  **************************************************************************/
 
-static inline int meta_get(struct sk_buff *skb, struct tcf_pkt_info *info, 
-                          struct meta_value *v, struct meta_obj *dst)
+static int meta_get(struct sk_buff *skb, struct tcf_pkt_info *info,
+                   struct meta_value *v, struct meta_obj *dst)
 {
        int err = 0;
 
@@ -724,25 +736,27 @@ static int em_meta_match(struct sk_buff *skb, struct tcf_ematch *m,
        return 0;
 }
 
-static inline void meta_delete(struct meta_match *meta)
+static void meta_delete(struct meta_match *meta)
 {
-       struct meta_type_ops *ops = meta_type_ops(&meta->lvalue);
+       if (meta) {
+               struct meta_type_ops *ops = meta_type_ops(&meta->lvalue);
 
-       if (ops && ops->destroy) {
-               ops->destroy(&meta->lvalue);
-               ops->destroy(&meta->rvalue);
+               if (ops && ops->destroy) {
+                       ops->destroy(&meta->lvalue);
+                       ops->destroy(&meta->rvalue);
+               }
        }
 
        kfree(meta);
 }
 
-static inline int meta_change_data(struct meta_value *dst, struct rtattr *rta)
+static inline int meta_change_data(struct meta_value *dst, struct nlattr *nla)
 {
-       if (rta) {
-               if (RTA_PAYLOAD(rta) == 0)
+       if (nla) {
+               if (nla_len(nla) == 0)
                        return -EINVAL;
 
-               return meta_type_ops(dst)->change(dst, rta);
+               return meta_type_ops(dst)->change(dst, nla);
        }
 
        return 0;
@@ -753,21 +767,26 @@ static inline int meta_is_supported(struct meta_value *val)
        return (!meta_id(val) || meta_ops(val)->get);
 }
 
+static const struct nla_policy meta_policy[TCA_EM_META_MAX + 1] = {
+       [TCA_EM_META_HDR]       = { .len = sizeof(struct tcf_meta_hdr) },
+};
+
 static int em_meta_change(struct tcf_proto *tp, void *data, int len,
                          struct tcf_ematch *m)
 {
-       int err = -EINVAL;
-       struct rtattr *tb[TCA_EM_META_MAX];
+       int err;
+       struct nlattr *tb[TCA_EM_META_MAX + 1];
        struct tcf_meta_hdr *hdr;
        struct meta_match *meta = NULL;
-       
-       if (rtattr_parse(tb, TCA_EM_META_MAX, data, len) < 0)
+
+       err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy);
+       if (err < 0)
                goto errout;
 
-       if (tb[TCA_EM_META_HDR-1] == NULL ||
-           RTA_PAYLOAD(tb[TCA_EM_META_HDR-1]) < sizeof(*hdr))
+       err = -EINVAL;
+       if (tb[TCA_EM_META_HDR] == NULL)
                goto errout;
-       hdr = RTA_DATA(tb[TCA_EM_META_HDR-1]);
+       hdr = nla_data(tb[TCA_EM_META_HDR]);
 
        if (TCF_META_TYPE(hdr->left.kind) != TCF_META_TYPE(hdr->right.kind) ||
            TCF_META_TYPE(hdr->left.kind) > TCF_META_TYPE_MAX ||
@@ -775,10 +794,9 @@ static int em_meta_change(struct tcf_proto *tp, void *data, int len,
            TCF_META_ID(hdr->right.kind) > TCF_META_ID_MAX)
                goto errout;
 
-       meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+       meta = kzalloc(sizeof(*meta), GFP_KERNEL);
        if (meta == NULL)
                goto errout;
-       memset(meta, 0, sizeof(*meta));
 
        memcpy(&meta->lvalue.hdr, &hdr->left, sizeof(hdr->left));
        memcpy(&meta->rvalue.hdr, &hdr->right, sizeof(hdr->right));
@@ -789,8 +807,8 @@ static int em_meta_change(struct tcf_proto *tp, void *data, int len,
                goto errout;
        }
 
-       if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE-1]) < 0 ||
-           meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE-1]) < 0)
+       if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE]) < 0 ||
+           meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE]) < 0)
                goto errout;
 
        m->datalen = sizeof(*meta);
@@ -819,18 +837,18 @@ static int em_meta_dump(struct sk_buff *skb, struct tcf_ematch *em)
        memcpy(&hdr.left, &meta->lvalue.hdr, sizeof(hdr.left));
        memcpy(&hdr.right, &meta->rvalue.hdr, sizeof(hdr.right));
 
-       RTA_PUT(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr);
+       NLA_PUT(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr);
 
        ops = meta_type_ops(&meta->lvalue);
        if (ops->dump(skb, &meta->lvalue, TCA_EM_META_LVALUE) < 0 ||
            ops->dump(skb, &meta->rvalue, TCA_EM_META_RVALUE) < 0)
-               goto rtattr_failure;
+               goto nla_put_failure;
 
        return 0;
 
-rtattr_failure:
+nla_put_failure:
        return -1;
-}              
+}
 
 static struct tcf_ematch_ops em_meta_ops = {
        .kind     = TCF_EM_META,
@@ -847,7 +865,7 @@ static int __init init_em_meta(void)
        return tcf_em_register(&em_meta_ops);
 }
 
-static void __exit exit_em_meta(void) 
+static void __exit exit_em_meta(void)
 {
        tcf_em_unregister(&em_meta_ops);
 }
@@ -856,3 +874,5 @@ MODULE_LICENSE("GPL");
 
 module_init(init_em_meta);
 module_exit(exit_em_meta);
+
+MODULE_ALIAS_TCF_EMATCH(TCF_EM_META);