HTB takes into account skb is segmented in stats updates.
Generalize this to all schedulers.
They should use qdisc_bstats_update() helper instead of manipulating
bstats.bytes and bstats.packets
Add bstats_update() helper too for classes that use
gnet_stats_basic_packed fields.
Note : Right now, TCQ_F_CAN_BYPASS shortcurt can be taken only if no
stab is setup on qdisc.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
        return q->q.qlen;
 }
 
-static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb)
+static inline struct qdisc_skb_cb *qdisc_skb_cb(const struct sk_buff *skb)
 {
        return (struct qdisc_skb_cb *)skb->cb;
 }
        return true;
 }
 
-static inline unsigned int qdisc_pkt_len(struct sk_buff *skb)
+static inline unsigned int qdisc_pkt_len(const struct sk_buff *skb)
 {
        return qdisc_skb_cb(skb)->pkt_len;
 }
        return qdisc_enqueue(skb, sch) & NET_XMIT_MASK;
 }
 
-static inline void __qdisc_update_bstats(struct Qdisc *sch, unsigned int len)
+
+static inline void bstats_update(struct gnet_stats_basic_packed *bstats,
+                                const struct sk_buff *skb)
+{
+       bstats->bytes += qdisc_pkt_len(skb);
+       bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
+}
+
+static inline void qdisc_bstats_update(struct Qdisc *sch,
+                                      const struct sk_buff *skb)
 {
-       sch->bstats.bytes += len;
-       sch->bstats.packets++;
+       bstats_update(&sch->bstats, skb);
 }
 
 static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 {
        __skb_queue_tail(list, skb);
        sch->qstats.backlog += qdisc_pkt_len(skb);
-       __qdisc_update_bstats(sch, qdisc_pkt_len(skb));
+       qdisc_bstats_update(sch, skb);
 
        return NET_XMIT_SUCCESS;
 }
 
                 */
                if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
                        skb_dst_force(skb);
-               __qdisc_update_bstats(q, skb->len);
+
+               qdisc_skb_cb(skb)->pkt_len = skb->len;
+               qdisc_bstats_update(q, skb);
+
                if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
                        if (unlikely(contended)) {
                                spin_unlock(&q->busylock);
 
 
        spin_lock(&p->tcf_lock);
        p->tcf_tm.lastuse = jiffies;
-       p->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       p->tcf_bstats.packets++;
+       bstats_update(&p->tcf_bstats, skb);
        action = p->tcf_action;
        update_flags = p->update_flags;
        spin_unlock(&p->tcf_lock);
 
        spin_lock(&ipt->tcf_lock);
 
        ipt->tcf_tm.lastuse = jiffies;
-       ipt->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       ipt->tcf_bstats.packets++;
+       bstats_update(&ipt->tcf_bstats, skb);
 
        /* yes, we have to worry about both in and out dev
         worry later - danger - this API seems to have changed
 
 
        spin_lock(&m->tcf_lock);
        m->tcf_tm.lastuse = jiffies;
-       m->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       m->tcf_bstats.packets++;
+       bstats_update(&m->tcf_bstats, skb);
 
        dev = m->tcfm_dev;
        if (!dev) {
 
        egress = p->flags & TCA_NAT_FLAG_EGRESS;
        action = p->tcf_action;
 
-       p->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       p->tcf_bstats.packets++;
+       bstats_update(&p->tcf_bstats, skb);
 
        spin_unlock(&p->tcf_lock);
 
 
 bad:
        p->tcf_qstats.overlimits++;
 done:
-       p->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       p->tcf_bstats.packets++;
+       bstats_update(&p->tcf_bstats, skb);
        spin_unlock(&p->tcf_lock);
        return p->tcf_action;
 }
 
 
        spin_lock(&police->tcf_lock);
 
-       police->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       police->tcf_bstats.packets++;
+       bstats_update(&police->tcf_bstats, skb);
 
        if (police->tcfp_ewma_rate &&
            police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
 
 
        spin_lock(&d->tcf_lock);
        d->tcf_tm.lastuse = jiffies;
-       d->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       d->tcf_bstats.packets++;
+       bstats_update(&d->tcf_bstats, skb);
 
        /* print policy string followed by _ then packet count
         * Example if this was the 3rd packet and the string was "hello"
 
 
        spin_lock(&d->tcf_lock);
        d->tcf_tm.lastuse = jiffies;
-       d->tcf_bstats.bytes += qdisc_pkt_len(skb);
-       d->tcf_bstats.packets++;
+       bstats_update(&d->tcf_bstats, skb);
 
        if (d->flags & SKBEDIT_F_PRIORITY)
                skb->priority = d->priority;
 
                }
                return ret;
        }
-       sch->bstats.bytes += qdisc_pkt_len(skb);
-       sch->bstats.packets++;
-       flow->bstats.bytes += qdisc_pkt_len(skb);
-       flow->bstats.packets++;
+       qdisc_bstats_update(sch, skb);
+       bstats_update(&flow->bstats, skb);
        /*
         * Okay, this may seem weird. We pretend we've dropped the packet if
         * it goes via ATM. The reason for this is that the outer qdisc
 
        ret = qdisc_enqueue(skb, cl->q);
        if (ret == NET_XMIT_SUCCESS) {
                sch->q.qlen++;
-               sch->bstats.packets++;
-               sch->bstats.bytes += qdisc_pkt_len(skb);
+               qdisc_bstats_update(sch, skb);
                cbq_mark_toplevel(q, cl);
                if (!cl->next_alive)
                        cbq_activate_class(cl);
                ret = qdisc_enqueue(skb, cl->q);
                if (ret == NET_XMIT_SUCCESS) {
                        sch->q.qlen++;
-                       sch->bstats.packets++;
-                       sch->bstats.bytes += qdisc_pkt_len(skb);
+                       qdisc_bstats_update(sch, skb);
                        if (!cl->next_alive)
                                cbq_activate_class(cl);
                        return 0;
 
 {
        struct drr_sched *q = qdisc_priv(sch);
        struct drr_class *cl;
-       unsigned int len;
        int err;
 
        cl = drr_classify(skb, sch, &err);
                return err;
        }
 
-       len = qdisc_pkt_len(skb);
        err = qdisc_enqueue(skb, cl->qdisc);
        if (unlikely(err != NET_XMIT_SUCCESS)) {
                if (net_xmit_drop_count(err)) {
                cl->deficit = cl->quantum;
        }
 
-       cl->bstats.packets++;
-       cl->bstats.bytes += len;
-       sch->bstats.packets++;
-       sch->bstats.bytes += len;
+       bstats_update(&cl->bstats, skb);
+       qdisc_bstats_update(sch, skb);
 
        sch->q.qlen++;
        return err;
 
                return err;
        }
 
-       sch->bstats.bytes += qdisc_pkt_len(skb);
-       sch->bstats.packets++;
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
 
        if (cl->qdisc->q.qlen == 1)
                set_active(cl, qdisc_pkt_len(skb));
 
-       cl->bstats.packets++;
-       cl->bstats.bytes += qdisc_pkt_len(skb);
-       sch->bstats.packets++;
-       sch->bstats.bytes += qdisc_pkt_len(skb);
+       bstats_update(&cl->bstats, skb);
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
 
                }
                return ret;
        } else {
-               cl->bstats.packets +=
-                       skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
-               cl->bstats.bytes += qdisc_pkt_len(skb);
+               bstats_update(&cl->bstats, skb);
                htb_activate(q, cl);
        }
 
        sch->q.qlen++;
-       sch->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
-       sch->bstats.bytes += qdisc_pkt_len(skb);
+       qdisc_bstats_update(sch, skb);
        return NET_XMIT_SUCCESS;
 }
 
                                htb_add_to_wait_tree(q, cl, diff);
                }
 
-               /* update byte stats except for leaves which are already updated */
-               if (cl->level) {
-                       cl->bstats.bytes += bytes;
-                       cl->bstats.packets += skb_is_gso(skb)?
-                                       skb_shinfo(skb)->gso_segs:1;
-               }
+               /* update basic stats except for leaves which are already updated */
+               if (cl->level)
+                       bstats_update(&cl->bstats, skb);
+
                cl = cl->parent;
        }
 }
 
 
        result = tc_classify(skb, p->filter_list, &res);
 
-       sch->bstats.packets++;
-       sch->bstats.bytes += qdisc_pkt_len(skb);
+       qdisc_bstats_update(sch, skb);
        switch (result) {
        case TC_ACT_SHOT:
                result = TC_ACT_SHOT;
 
 
        ret = qdisc_enqueue(skb, qdisc);
        if (ret == NET_XMIT_SUCCESS) {
-               sch->bstats.bytes += qdisc_pkt_len(skb);
-               sch->bstats.packets++;
+               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
                return NET_XMIT_SUCCESS;
        }
 
 
        if (likely(ret == NET_XMIT_SUCCESS)) {
                sch->q.qlen++;
-               sch->bstats.bytes += qdisc_pkt_len(skb);
-               sch->bstats.packets++;
+               qdisc_bstats_update(sch, skb);
        } else if (net_xmit_drop_count(ret)) {
                sch->qstats.drops++;
        }
                __skb_queue_after(list, skb, nskb);
 
                sch->qstats.backlog += qdisc_pkt_len(nskb);
-               sch->bstats.bytes += qdisc_pkt_len(nskb);
-               sch->bstats.packets++;
+               qdisc_bstats_update(sch, nskb);
 
                return NET_XMIT_SUCCESS;
        }
 
 
        ret = qdisc_enqueue(skb, qdisc);
        if (ret == NET_XMIT_SUCCESS) {
-               sch->bstats.bytes += qdisc_pkt_len(skb);
-               sch->bstats.packets++;
+               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
                return NET_XMIT_SUCCESS;
        }
 
 
        ret = qdisc_enqueue(skb, child);
        if (likely(ret == NET_XMIT_SUCCESS)) {
-               sch->bstats.bytes += qdisc_pkt_len(skb);
-               sch->bstats.packets++;
+               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
        } else if (net_xmit_drop_count(ret)) {
                q->stats.pdrop++;
 
                slot->allot = q->scaled_quantum;
        }
        if (++sch->q.qlen <= q->limit) {
-               sch->bstats.bytes += qdisc_pkt_len(skb);
-               sch->bstats.packets++;
+               qdisc_bstats_update(sch, skb);
                return NET_XMIT_SUCCESS;
        }
 
 
        }
 
        sch->q.qlen++;
-       sch->bstats.bytes += qdisc_pkt_len(skb);
-       sch->bstats.packets++;
+       qdisc_bstats_update(sch, skb);
        return NET_XMIT_SUCCESS;
 }
 
 
 
        if (q->q.qlen < dev->tx_queue_len) {
                __skb_queue_tail(&q->q, skb);
-               sch->bstats.bytes += qdisc_pkt_len(skb);
-               sch->bstats.packets++;
+               qdisc_bstats_update(sch, skb);
                return NET_XMIT_SUCCESS;
        }