Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7d2681a6ff4f9ab5e48d02550b4c6338f1638998
Commit:     7d2681a6ff4f9ab5e48d02550b4c6338f1638998
Parent:     5239008b0de2507a531440b8c3019fb9c116fb1a
Author:     Patrick McHardy <[EMAIL PROTECTED]>
AuthorDate: Thu Jan 31 18:36:52 2008 -0800
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Thu Jan 31 19:28:34 2008 -0800

    [NET_SCHED]: sch_sfq: add support for external classifiers
    
    Add support for external classifiers to allow using different flow
    hash functions similar to ESFQ. When no classifier is attached the
    built-in hash is used as before.
    
    Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 net/sched/sch_sfq.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 91af539..d818d19 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -95,6 +95,7 @@ struct sfq_sched_data
        int             limit;
 
 /* Variables */
+       struct tcf_proto *filter_list;
        struct timer_list perturb_timer;
        u32             perturbation;
        sfq_index       tail;           /* Index of current slot in round */
@@ -155,6 +156,39 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct 
sk_buff *skb)
        return sfq_fold_hash(q, h, h2);
 }
 
+static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
+                                int *qerr)
+{
+       struct sfq_sched_data *q = qdisc_priv(sch);
+       struct tcf_result res;
+       int result;
+
+       if (TC_H_MAJ(skb->priority) == sch->handle &&
+           TC_H_MIN(skb->priority) > 0 &&
+           TC_H_MIN(skb->priority) <= SFQ_HASH_DIVISOR)
+               return TC_H_MIN(skb->priority);
+
+       if (!q->filter_list)
+               return sfq_hash(q, skb) + 1;
+
+       *qerr = NET_XMIT_BYPASS;
+       result = tc_classify(skb, q->filter_list, &res);
+       if (result >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+               switch (result) {
+               case TC_ACT_STOLEN:
+               case TC_ACT_QUEUED:
+                       *qerr = NET_XMIT_SUCCESS;
+               case TC_ACT_SHOT:
+                       return 0;
+               }
+#endif
+               if (TC_H_MIN(res.classid) <= SFQ_HASH_DIVISOR)
+                       return TC_H_MIN(res.classid);
+       }
+       return 0;
+}
+
 static inline void sfq_link(struct sfq_sched_data *q, sfq_index x)
 {
        sfq_index p, n;
@@ -245,8 +279,18 @@ static int
 sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
-       unsigned hash = sfq_hash(q, skb);
+       unsigned int hash;
        sfq_index x;
+       int ret;
+
+       hash = sfq_classify(skb, sch, &ret);
+       if (hash == 0) {
+               if (ret == NET_XMIT_BYPASS)
+                       sch->qstats.drops++;
+               kfree_skb(skb);
+               return ret;
+       }
+       hash--;
 
        x = q->ht[hash];
        if (x == SFQ_DEPTH) {
@@ -289,8 +333,18 @@ static int
 sfq_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
-       unsigned hash = sfq_hash(q, skb);
+       unsigned int hash;
        sfq_index x;
+       int ret;
+
+       hash = sfq_classify(skb, sch, &ret);
+       if (hash == 0) {
+               if (ret == NET_XMIT_BYPASS)
+                       sch->qstats.drops++;
+               kfree_skb(skb);
+               return ret;
+       }
+       hash--;
 
        x = q->ht[hash];
        if (x == SFQ_DEPTH) {
@@ -465,6 +519,8 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
 static void sfq_destroy(struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
+
+       tcf_destroy_chain(q->filter_list);
        del_timer(&q->perturb_timer);
 }
 
@@ -490,9 +546,40 @@ nla_put_failure:
        return -1;
 }
 
+static int sfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+                           struct nlattr **tca, unsigned long *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static unsigned long sfq_get(struct Qdisc *sch, u32 classid)
+{
+       return 0;
+}
+
+static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl)
+{
+       struct sfq_sched_data *q = qdisc_priv(sch);
+
+       if (cl)
+               return NULL;
+       return &q->filter_list;
+}
+
+static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+       return;
+}
+
+static const struct Qdisc_class_ops sfq_class_ops = {
+       .get            =       sfq_get,
+       .change         =       sfq_change_class,
+       .tcf_chain      =       sfq_find_tcf,
+       .walk           =       sfq_walk,
+};
+
 static struct Qdisc_ops sfq_qdisc_ops __read_mostly = {
-       .next           =       NULL,
-       .cl_ops         =       NULL,
+       .cl_ops         =       &sfq_class_ops,
        .id             =       "sfq",
        .priv_size      =       sizeof(struct sfq_sched_data),
        .enqueue        =       sfq_enqueue,
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to