pkt_sched: pedit use proper struct
[safe/jmp/linux-2.6] / net / sched / cls_flow.c
index 8d76986..9402a7f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/if_vlan.h>
 
 #include <net/pkt_cls.h>
 #include <net/ip.h>
@@ -35,6 +36,8 @@ struct flow_filter {
        struct list_head        list;
        struct tcf_exts         exts;
        struct tcf_ematch_tree  ematches;
+       struct timer_list       perturb_timer;
+       u32                     perturb_period;
        u32                     handle;
 
        u32                     nkeys;
@@ -46,11 +49,9 @@ struct flow_filter {
        u32                     addend;
        u32                     divisor;
        u32                     baseclass;
+       u32                     hashrnd;
 };
 
-static u32 flow_hashrnd __read_mostly;
-static int flow_hashrnd_initted __read_mostly;
-
 static const struct tcf_ext_map flow_ext_map = {
        .action = TCA_FLOW_ACT,
        .police = TCA_FLOW_POLICE,
@@ -66,9 +67,9 @@ static inline u32 addr_fold(void *addr)
 static u32 flow_get_src(const struct sk_buff *skb)
 {
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_IP):
+       case htons(ETH_P_IP):
                return ntohl(ip_hdr(skb)->saddr);
-       case __constant_htons(ETH_P_IPV6):
+       case htons(ETH_P_IPV6):
                return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]);
        default:
                return addr_fold(skb->sk);
@@ -78,21 +79,21 @@ static u32 flow_get_src(const struct sk_buff *skb)
 static u32 flow_get_dst(const struct sk_buff *skb)
 {
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_IP):
+       case htons(ETH_P_IP):
                return ntohl(ip_hdr(skb)->daddr);
-       case __constant_htons(ETH_P_IPV6):
+       case htons(ETH_P_IPV6):
                return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]);
        default:
-               return addr_fold(skb->dst) ^ (__force u16)skb->protocol;
+               return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
        }
 }
 
 static u32 flow_get_proto(const struct sk_buff *skb)
 {
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_IP):
+       case htons(ETH_P_IP):
                return ip_hdr(skb)->protocol;
-       case __constant_htons(ETH_P_IPV6):
+       case htons(ETH_P_IPV6):
                return ipv6_hdr(skb)->nexthdr;
        default:
                return 0;
@@ -119,7 +120,7 @@ static u32 flow_get_proto_src(const struct sk_buff *skb)
        u32 res = 0;
 
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_IP): {
+       case htons(ETH_P_IP): {
                struct iphdr *iph = ip_hdr(skb);
 
                if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
@@ -127,7 +128,7 @@ static u32 flow_get_proto_src(const struct sk_buff *skb)
                        res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
                break;
        }
-       case __constant_htons(ETH_P_IPV6): {
+       case htons(ETH_P_IPV6): {
                struct ipv6hdr *iph = ipv6_hdr(skb);
 
                if (has_ports(iph->nexthdr))
@@ -146,7 +147,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb)
        u32 res = 0;
 
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_IP): {
+       case htons(ETH_P_IP): {
                struct iphdr *iph = ip_hdr(skb);
 
                if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
@@ -154,7 +155,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb)
                        res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
                break;
        }
-       case __constant_htons(ETH_P_IPV6): {
+       case htons(ETH_P_IPV6): {
                struct ipv6hdr *iph = ipv6_hdr(skb);
 
                if (has_ports(iph->nexthdr))
@@ -162,7 +163,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb)
                break;
        }
        default:
-               res = addr_fold(skb->dst) ^ (__force u16)skb->protocol;
+               res = addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
        }
 
        return res;
@@ -212,9 +213,9 @@ static u32 flow_get_nfct(const struct sk_buff *skb)
 static u32 flow_get_nfct_src(const struct sk_buff *skb)
 {
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_IP):
+       case htons(ETH_P_IP):
                return ntohl(CTTUPLE(skb, src.u3.ip));
-       case __constant_htons(ETH_P_IPV6):
+       case htons(ETH_P_IPV6):
                return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
        }
 fallback:
@@ -224,9 +225,9 @@ fallback:
 static u32 flow_get_nfct_dst(const struct sk_buff *skb)
 {
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_IP):
+       case htons(ETH_P_IP):
                return ntohl(CTTUPLE(skb, dst.u3.ip));
-       case __constant_htons(ETH_P_IPV6):
+       case htons(ETH_P_IPV6):
                return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
        }
 fallback:
@@ -250,8 +251,8 @@ fallback:
 static u32 flow_get_rtclassid(const struct sk_buff *skb)
 {
 #ifdef CONFIG_NET_CLS_ROUTE
-       if (skb->dst)
-               return skb->dst->tclassid;
+       if (skb_dst(skb))
+               return skb_dst(skb)->tclassid;
 #endif
        return 0;
 }
@@ -259,17 +260,26 @@ static u32 flow_get_rtclassid(const struct sk_buff *skb)
 static u32 flow_get_skuid(const struct sk_buff *skb)
 {
        if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
-               return skb->sk->sk_socket->file->f_uid;
+               return skb->sk->sk_socket->file->f_cred->fsuid;
        return 0;
 }
 
 static u32 flow_get_skgid(const struct sk_buff *skb)
 {
        if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
-               return skb->sk->sk_socket->file->f_gid;
+               return skb->sk->sk_socket->file->f_cred->fsgid;
        return 0;
 }
 
+static u32 flow_get_vlan_tag(const struct sk_buff *skb)
+{
+       u16 uninitialized_var(tag);
+
+       if (vlan_get_tag(skb, &tag) < 0)
+               return 0;
+       return tag & VLAN_VID_MASK;
+}
+
 static u32 flow_key_get(const struct sk_buff *skb, int key)
 {
        switch (key) {
@@ -305,6 +315,8 @@ static u32 flow_key_get(const struct sk_buff *skb, int key)
                return flow_get_skuid(skb);
        case FLOW_KEY_SKGID:
                return flow_get_skgid(skb);
+       case FLOW_KEY_VLAN_TAG:
+               return flow_get_vlan_tag(skb);
        default:
                WARN_ON(1);
                return 0;
@@ -336,7 +348,7 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
                }
 
                if (f->mode == FLOW_MODE_HASH)
-                       classid = jhash2(keys, f->nkeys, flow_hashrnd);
+                       classid = jhash2(keys, f->nkeys, f->hashrnd);
                else {
                        classid = keys[0];
                        classid = (classid & f->mask) ^ f->xor;
@@ -357,6 +369,15 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
        return -1;
 }
 
+static void flow_perturbation(unsigned long arg)
+{
+       struct flow_filter *f = (struct flow_filter *)arg;
+
+       get_random_bytes(&f->hashrnd, 4);
+       if (f->perturb_period)
+               mod_timer(&f->perturb_timer, jiffies + f->perturb_period);
+}
+
 static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
        [TCA_FLOW_KEYS]         = { .type = NLA_U32 },
        [TCA_FLOW_MODE]         = { .type = NLA_U32 },
@@ -369,6 +390,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
        [TCA_FLOW_ACT]          = { .type = NLA_NESTED },
        [TCA_FLOW_POLICE]       = { .type = NLA_NESTED },
        [TCA_FLOW_EMATCHES]     = { .type = NLA_NESTED },
+       [TCA_FLOW_PERTURB]      = { .type = NLA_U32 },
 };
 
 static int flow_change(struct tcf_proto *tp, unsigned long base,
@@ -382,6 +404,7 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
        struct tcf_exts e;
        struct tcf_ematch_tree t;
        unsigned int nkeys = 0;
+       unsigned int perturb_period = 0;
        u32 baseclass = 0;
        u32 keymask = 0;
        u32 mode;
@@ -402,12 +425,13 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
 
        if (tb[TCA_FLOW_KEYS]) {
                keymask = nla_get_u32(tb[TCA_FLOW_KEYS]);
-               if (fls(keymask) - 1 > FLOW_KEY_MAX)
-                       return -EOPNOTSUPP;
 
                nkeys = hweight32(keymask);
                if (nkeys == 0)
                        return -EINVAL;
+
+               if (fls(keymask) - 1 > FLOW_KEY_MAX)
+                       return -EOPNOTSUPP;
        }
 
        err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
@@ -429,6 +453,14 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
                        mode = nla_get_u32(tb[TCA_FLOW_MODE]);
                if (mode != FLOW_MODE_HASH && nkeys > 1)
                        goto err2;
+
+               if (mode == FLOW_MODE_HASH)
+                       perturb_period = f->perturb_period;
+               if (tb[TCA_FLOW_PERTURB]) {
+                       if (mode != FLOW_MODE_HASH)
+                               goto err2;
+                       perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
+               }
        } else {
                err = -EINVAL;
                if (!handle)
@@ -442,6 +474,12 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
                if (mode != FLOW_MODE_HASH && nkeys > 1)
                        goto err2;
 
+               if (tb[TCA_FLOW_PERTURB]) {
+                       if (mode != FLOW_MODE_HASH)
+                               goto err2;
+                       perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
+               }
+
                if (TC_H_MAJ(baseclass) == 0)
                        baseclass = TC_H_MAKE(tp->q->handle, baseclass);
                if (TC_H_MIN(baseclass) == 0)
@@ -454,6 +492,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
 
                f->handle = handle;
                f->mask   = ~0U;
+
+               get_random_bytes(&f->hashrnd, 4);
+               f->perturb_timer.function = flow_perturbation;
+               f->perturb_timer.data = (unsigned long)f;
+               init_timer_deferrable(&f->perturb_timer);
        }
 
        tcf_exts_change(tp, &f->exts, &e);
@@ -482,6 +525,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
        if (baseclass)
                f->baseclass = baseclass;
 
+       f->perturb_period = perturb_period;
+       del_timer(&f->perturb_timer);
+       if (perturb_period)
+               mod_timer(&f->perturb_timer, jiffies + perturb_period);
+
        if (*arg == 0)
                list_add_tail(&f->list, &head->filters);
 
@@ -499,6 +547,7 @@ err1:
 
 static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f)
 {
+       del_timer_sync(&f->perturb_timer);
        tcf_exts_destroy(tp, &f->exts);
        tcf_em_tree_destroy(tp, &f->ematches);
        kfree(f);
@@ -519,11 +568,6 @@ static int flow_init(struct tcf_proto *tp)
 {
        struct flow_head *head;
 
-       if (!flow_hashrnd_initted) {
-               get_random_bytes(&flow_hashrnd, 4);
-               flow_hashrnd_initted = 1;
-       }
-
        head = kzalloc(sizeof(*head), GFP_KERNEL);
        if (head == NULL)
                return -ENOBUFS;
@@ -592,6 +636,9 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh,
        if (f->baseclass)
                NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass);
 
+       if (f->perturb_period)
+               NLA_PUT_U32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ);
+
        if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
                goto nla_put_failure;
 #ifdef CONFIG_NET_EMATCH