diff options
| -rw-r--r-- | 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 91af539ab6e6..d818d1985cca 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c | |||
| @@ -95,6 +95,7 @@ struct sfq_sched_data | |||
| 95 | int limit; | 95 | int limit; |
| 96 | 96 | ||
| 97 | /* Variables */ | 97 | /* Variables */ |
| 98 | struct tcf_proto *filter_list; | ||
| 98 | struct timer_list perturb_timer; | 99 | struct timer_list perturb_timer; |
| 99 | u32 perturbation; | 100 | u32 perturbation; |
| 100 | sfq_index tail; /* Index of current slot in round */ | 101 | 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) | |||
| 155 | return sfq_fold_hash(q, h, h2); | 156 | return sfq_fold_hash(q, h, h2); |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 159 | static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch, | ||
| 160 | int *qerr) | ||
| 161 | { | ||
| 162 | struct sfq_sched_data *q = qdisc_priv(sch); | ||
| 163 | struct tcf_result res; | ||
| 164 | int result; | ||
| 165 | |||
| 166 | if (TC_H_MAJ(skb->priority) == sch->handle && | ||
| 167 | TC_H_MIN(skb->priority) > 0 && | ||
| 168 | TC_H_MIN(skb->priority) <= SFQ_HASH_DIVISOR) | ||
| 169 | return TC_H_MIN(skb->priority); | ||
| 170 | |||
| 171 | if (!q->filter_list) | ||
| 172 | return sfq_hash(q, skb) + 1; | ||
| 173 | |||
| 174 | *qerr = NET_XMIT_BYPASS; | ||
| 175 | result = tc_classify(skb, q->filter_list, &res); | ||
| 176 | if (result >= 0) { | ||
| 177 | #ifdef CONFIG_NET_CLS_ACT | ||
| 178 | switch (result) { | ||
| 179 | case TC_ACT_STOLEN: | ||
| 180 | case TC_ACT_QUEUED: | ||
| 181 | *qerr = NET_XMIT_SUCCESS; | ||
| 182 | case TC_ACT_SHOT: | ||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | #endif | ||
| 186 | if (TC_H_MIN(res.classid) <= SFQ_HASH_DIVISOR) | ||
| 187 | return TC_H_MIN(res.classid); | ||
| 188 | } | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 158 | static inline void sfq_link(struct sfq_sched_data *q, sfq_index x) | 192 | static inline void sfq_link(struct sfq_sched_data *q, sfq_index x) |
| 159 | { | 193 | { |
| 160 | sfq_index p, n; | 194 | sfq_index p, n; |
| @@ -245,8 +279,18 @@ static int | |||
| 245 | sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | 279 | sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
| 246 | { | 280 | { |
| 247 | struct sfq_sched_data *q = qdisc_priv(sch); | 281 | struct sfq_sched_data *q = qdisc_priv(sch); |
| 248 | unsigned hash = sfq_hash(q, skb); | 282 | unsigned int hash; |
| 249 | sfq_index x; | 283 | sfq_index x; |
| 284 | int ret; | ||
| 285 | |||
| 286 | hash = sfq_classify(skb, sch, &ret); | ||
| 287 | if (hash == 0) { | ||
| 288 | if (ret == NET_XMIT_BYPASS) | ||
| 289 | sch->qstats.drops++; | ||
| 290 | kfree_skb(skb); | ||
| 291 | return ret; | ||
| 292 | } | ||
| 293 | hash--; | ||
| 250 | 294 | ||
| 251 | x = q->ht[hash]; | 295 | x = q->ht[hash]; |
| 252 | if (x == SFQ_DEPTH) { | 296 | if (x == SFQ_DEPTH) { |
| @@ -289,8 +333,18 @@ static int | |||
| 289 | sfq_requeue(struct sk_buff *skb, struct Qdisc *sch) | 333 | sfq_requeue(struct sk_buff *skb, struct Qdisc *sch) |
| 290 | { | 334 | { |
| 291 | struct sfq_sched_data *q = qdisc_priv(sch); | 335 | struct sfq_sched_data *q = qdisc_priv(sch); |
| 292 | unsigned hash = sfq_hash(q, skb); | 336 | unsigned int hash; |
| 293 | sfq_index x; | 337 | sfq_index x; |
| 338 | int ret; | ||
| 339 | |||
| 340 | hash = sfq_classify(skb, sch, &ret); | ||
| 341 | if (hash == 0) { | ||
| 342 | if (ret == NET_XMIT_BYPASS) | ||
| 343 | sch->qstats.drops++; | ||
| 344 | kfree_skb(skb); | ||
| 345 | return ret; | ||
| 346 | } | ||
| 347 | hash--; | ||
| 294 | 348 | ||
| 295 | x = q->ht[hash]; | 349 | x = q->ht[hash]; |
| 296 | if (x == SFQ_DEPTH) { | 350 | if (x == SFQ_DEPTH) { |
| @@ -465,6 +519,8 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 465 | static void sfq_destroy(struct Qdisc *sch) | 519 | static void sfq_destroy(struct Qdisc *sch) |
| 466 | { | 520 | { |
| 467 | struct sfq_sched_data *q = qdisc_priv(sch); | 521 | struct sfq_sched_data *q = qdisc_priv(sch); |
| 522 | |||
| 523 | tcf_destroy_chain(q->filter_list); | ||
| 468 | del_timer(&q->perturb_timer); | 524 | del_timer(&q->perturb_timer); |
| 469 | } | 525 | } |
| 470 | 526 | ||
| @@ -490,9 +546,40 @@ nla_put_failure: | |||
| 490 | return -1; | 546 | return -1; |
| 491 | } | 547 | } |
| 492 | 548 | ||
| 549 | static int sfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | ||
| 550 | struct nlattr **tca, unsigned long *arg) | ||
| 551 | { | ||
| 552 | return -EOPNOTSUPP; | ||
| 553 | } | ||
| 554 | |||
| 555 | static unsigned long sfq_get(struct Qdisc *sch, u32 classid) | ||
| 556 | { | ||
| 557 | return 0; | ||
| 558 | } | ||
| 559 | |||
| 560 | static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl) | ||
| 561 | { | ||
| 562 | struct sfq_sched_data *q = qdisc_priv(sch); | ||
| 563 | |||
| 564 | if (cl) | ||
| 565 | return NULL; | ||
| 566 | return &q->filter_list; | ||
| 567 | } | ||
| 568 | |||
| 569 | static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg) | ||
| 570 | { | ||
| 571 | return; | ||
| 572 | } | ||
| 573 | |||
| 574 | static const struct Qdisc_class_ops sfq_class_ops = { | ||
| 575 | .get = sfq_get, | ||
| 576 | .change = sfq_change_class, | ||
| 577 | .tcf_chain = sfq_find_tcf, | ||
| 578 | .walk = sfq_walk, | ||
| 579 | }; | ||
| 580 | |||
| 493 | static struct Qdisc_ops sfq_qdisc_ops __read_mostly = { | 581 | static struct Qdisc_ops sfq_qdisc_ops __read_mostly = { |
| 494 | .next = NULL, | 582 | .cl_ops = &sfq_class_ops, |
| 495 | .cl_ops = NULL, | ||
| 496 | .id = "sfq", | 583 | .id = "sfq", |
| 497 | .priv_size = sizeof(struct sfq_sched_data), | 584 | .priv_size = sizeof(struct sfq_sched_data), |
| 498 | .enqueue = sfq_enqueue, | 585 | .enqueue = sfq_enqueue, |
