/* TODO: requeuing packet charges it to policers again !! */
static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
{
+ int ret;
struct htb_sched *q = qdisc_priv(sch);
- int ret = NET_XMIT_SUCCESS;
struct htb_class *cl = htb_classify(skb, sch, &ret);
struct sk_buff *tskb;
- if (cl == HTB_DIRECT || !cl) {
+ if (cl == HTB_DIRECT) {
/* enqueue to helper queue */
- if (q->direct_queue.qlen < q->direct_qlen && cl) {
+ if (q->direct_queue.qlen < q->direct_qlen) {
__skb_queue_head(&q->direct_queue, skb);
} else {
__skb_queue_head(&q->direct_queue, skb);
sch->qstats.drops++;
return NET_XMIT_CN;
}
+#ifdef CONFIG_NET_CLS_ACT
+ } else if (!cl) {
+ if (ret == NET_XMIT_BYPASS)
+ sch->qstats.drops++;
+ kfree_skb(skb);
+ return ret;
+#endif
} else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) !=
NET_XMIT_SUCCESS) {
sch->qstats.drops++;
*/
static psched_time_t htb_do_events(struct htb_sched *q, int level)
{
- int i;
-
- for (i = 0; i < 500; i++) {
+ /* don't run for longer than 2 jiffies; 2 is used instead of
+ 1 to simplify things when jiffy is going to be incremented
+ too soon */
+ unsigned long stop_at = jiffies + 2;
+ while (time_before(jiffies, stop_at)) {
struct htb_class *cl;
long diff;
struct rb_node *p = rb_first(&q->wait_pq[level]);
if (cl->cmode != HTB_CAN_SEND)
htb_add_to_wait_tree(q, cl, diff);
}
- if (net_ratelimit())
- printk(KERN_WARNING "htb: too many events !\n");
- return q->now + PSCHED_TICKS_PER_SEC / 10;
+ /* too much load - let's continue on next jiffie */
+ return q->now + PSCHED_TICKS_PER_SEC / HZ;
}
/* Returns class->node+prio from id-tree where classe's id is >= id. NULL
INIT_LIST_HEAD(q->drops + i);
}
+static const struct nla_policy htb_policy[TCA_HTB_MAX + 1] = {
+ [TCA_HTB_PARMS] = { .len = sizeof(struct tc_htb_opt) },
+ [TCA_HTB_INIT] = { .len = sizeof(struct tc_htb_glob) },
+ [TCA_HTB_CTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
+ [TCA_HTB_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
+};
+
static int htb_init(struct Qdisc *sch, struct nlattr *opt)
{
struct htb_sched *q = qdisc_priv(sch);
if (!opt)
return -EINVAL;
- err = nla_parse_nested(tb, TCA_HTB_INIT, opt, NULL);
+ err = nla_parse_nested(tb, TCA_HTB_INIT, opt, htb_policy);
if (err < 0)
return err;
- if (tb[TCA_HTB_INIT] == NULL ||
- nla_len(tb[TCA_HTB_INIT]) < sizeof(*gopt)) {
+ if (tb[TCA_HTB_INIT] == NULL) {
printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n");
return -EINVAL;
}
static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
{
struct htb_sched *q = qdisc_priv(sch);
- unsigned char *b = skb_tail_pointer(skb);
- struct nlattr *nla;
+ struct nlattr *nest;
struct tc_htb_glob gopt;
+
spin_lock_bh(&sch->dev->queue_lock);
- gopt.direct_pkts = q->direct_pkts;
+ gopt.direct_pkts = q->direct_pkts;
gopt.version = HTB_VER;
gopt.rate2quantum = q->rate2quantum;
gopt.defcls = q->defcls;
gopt.debug = 0;
- nla = (struct nlattr *)b;
- NLA_PUT(skb, TCA_OPTIONS, 0, NULL);
+
+ nest = nla_nest_start(skb, TCA_OPTIONS);
+ if (nest == NULL)
+ goto nla_put_failure;
NLA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt);
- nla->nla_len = skb_tail_pointer(skb) - b;
+ nla_nest_end(skb, nest);
+
spin_unlock_bh(&sch->dev->queue_lock);
return skb->len;
+
nla_put_failure:
spin_unlock_bh(&sch->dev->queue_lock);
- nlmsg_trim(skb, skb_tail_pointer(skb));
+ nla_nest_cancel(skb, nest);
return -1;
}
struct sk_buff *skb, struct tcmsg *tcm)
{
struct htb_class *cl = (struct htb_class *)arg;
- unsigned char *b = skb_tail_pointer(skb);
- struct nlattr *nla;
+ struct nlattr *nest;
struct tc_htb_opt opt;
spin_lock_bh(&sch->dev->queue_lock);
if (!cl->level && cl->un.leaf.q)
tcm->tcm_info = cl->un.leaf.q->handle;
- nla = (struct nlattr *)b;
- NLA_PUT(skb, TCA_OPTIONS, 0, NULL);
+ nest = nla_nest_start(skb, TCA_OPTIONS);
+ if (nest == NULL)
+ goto nla_put_failure;
memset(&opt, 0, sizeof(opt));
opt.prio = cl->un.leaf.prio;
opt.level = cl->level;
NLA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
- nla->nla_len = skb_tail_pointer(skb) - b;
+
+ nla_nest_end(skb, nest);
spin_unlock_bh(&sch->dev->queue_lock);
return skb->len;
+
nla_put_failure:
spin_unlock_bh(&sch->dev->queue_lock);
- nlmsg_trim(skb, b);
+ nla_nest_cancel(skb, nest);
return -1;
}
if (!opt)
goto failure;
- err = nla_parse_nested(tb, TCA_HTB_RTAB, opt, NULL);
+ err = nla_parse_nested(tb, TCA_HTB_RTAB, opt, htb_policy);
if (err < 0)
goto failure;
err = -EINVAL;
- if (tb[TCA_HTB_PARMS] == NULL ||
- nla_len(tb[TCA_HTB_PARMS]) < sizeof(*hopt))
+ if (tb[TCA_HTB_PARMS] == NULL)
goto failure;
parent = parentid == TC_H_ROOT ? NULL : htb_find(parentid, sch);