int refcnt;
};
+enum qdisc_state_t
+{
+ __QDISC_STATE_RUNNING,
+ __QDISC_STATE_SCHED,
+};
+
+struct qdisc_size_table {
+ struct list_head list;
+ struct tc_sizespec szopts;
+ int refcnt;
+ u16 data[];
+};
+
struct Qdisc
{
int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
#define TCQ_F_INGRESS 4
int padded;
struct Qdisc_ops *ops;
+ struct qdisc_size_table *stab;
u32 handle;
u32 parent;
atomic_t refcnt;
+ unsigned long state;
+ struct sk_buff *gso_skb;
struct sk_buff_head q;
- struct net_device *dev;
+ struct netdev_queue *dev_queue;
+ struct Qdisc *next_sched;
struct list_head list;
struct gnet_stats_basic bstats;
struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est;
- spinlock_t *stats_lock;
struct rcu_head q_rcu;
int (*reshape_fail)(struct sk_buff *skb,
struct Qdisc *q);
+ void *u32_node;
+
/* This field is deprecated, but it is still used by CBQ
* and it will live until better solution will be invented.
*/
unsigned long (*get)(struct Qdisc *, u32 classid);
void (*put)(struct Qdisc *, unsigned long);
int (*change)(struct Qdisc *, u32, u32,
- struct rtattr **, unsigned long *);
+ struct nlattr **, unsigned long *);
int (*delete)(struct Qdisc *, unsigned long);
void (*walk)(struct Qdisc *, struct qdisc_walker * arg);
struct Qdisc_ops
{
struct Qdisc_ops *next;
- struct Qdisc_class_ops *cl_ops;
+ const struct Qdisc_class_ops *cl_ops;
char id[IFNAMSIZ];
int priv_size;
int (*requeue)(struct sk_buff *, struct Qdisc *);
unsigned int (*drop)(struct Qdisc *);
- int (*init)(struct Qdisc *, struct rtattr *arg);
+ int (*init)(struct Qdisc *, struct nlattr *arg);
void (*reset)(struct Qdisc *);
void (*destroy)(struct Qdisc *);
- int (*change)(struct Qdisc *, struct rtattr *arg);
+ int (*change)(struct Qdisc *, struct nlattr *arg);
int (*dump)(struct Qdisc *, struct sk_buff *);
int (*dump_stats)(struct Qdisc *, struct gnet_dump *);
unsigned long (*get)(struct tcf_proto*, u32 handle);
void (*put)(struct tcf_proto*, unsigned long);
int (*change)(struct tcf_proto*, unsigned long,
- u32 handle, struct rtattr **,
+ u32 handle, struct nlattr **,
unsigned long *);
int (*delete)(struct tcf_proto*, unsigned long);
void (*walk)(struct tcf_proto*, struct tcf_walker *arg);
struct tcf_proto_ops *ops;
};
+struct qdisc_skb_cb {
+ unsigned int pkt_len;
+ char data[];
+};
+
+static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb)
+{
+ return (struct qdisc_skb_cb *)skb->cb;
+}
+
+static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc)
+{
+ return &qdisc->q.lock;
+}
+
+static inline struct Qdisc *qdisc_root(struct Qdisc *qdisc)
+{
+ return qdisc->dev_queue->qdisc;
+}
+
+static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc)
+{
+ struct Qdisc *root = qdisc_root(qdisc);
+
+ return qdisc_lock(root);
+}
+
+static inline struct net_device *qdisc_dev(struct Qdisc *qdisc)
+{
+ return qdisc->dev_queue->dev;
+}
+
+static inline void sch_tree_lock(struct Qdisc *q)
+{
+ spin_lock_bh(qdisc_root_lock(q));
+}
-extern void qdisc_lock_tree(struct net_device *dev);
-extern void qdisc_unlock_tree(struct net_device *dev);
+static inline void sch_tree_unlock(struct Qdisc *q)
+{
+ spin_unlock_bh(qdisc_root_lock(q));
+}
-#define sch_tree_lock(q) qdisc_lock_tree((q)->dev)
-#define sch_tree_unlock(q) qdisc_unlock_tree((q)->dev)
-#define tcf_tree_lock(tp) qdisc_lock_tree((tp)->q->dev)
-#define tcf_tree_unlock(tp) qdisc_unlock_tree((tp)->q->dev)
+#define tcf_tree_lock(tp) sch_tree_lock((tp)->q)
+#define tcf_tree_unlock(tp) sch_tree_unlock((tp)->q)
extern struct Qdisc noop_qdisc;
extern struct Qdisc_ops noop_qdisc_ops;
+struct Qdisc_class_common
+{
+ u32 classid;
+ struct hlist_node hnode;
+};
+
+struct Qdisc_class_hash
+{
+ struct hlist_head *hash;
+ unsigned int hashsize;
+ unsigned int hashmask;
+ unsigned int hashelems;
+};
+
+static inline unsigned int qdisc_class_hash(u32 id, u32 mask)
+{
+ id ^= id >> 8;
+ id ^= id >> 4;
+ return id & mask;
+}
+
+static inline struct Qdisc_class_common *
+qdisc_class_find(struct Qdisc_class_hash *hash, u32 id)
+{
+ struct Qdisc_class_common *cl;
+ struct hlist_node *n;
+ unsigned int h;
+
+ h = qdisc_class_hash(id, hash->hashmask);
+ hlist_for_each_entry(cl, n, &hash->hash[h], hnode) {
+ if (cl->classid == id)
+ return cl;
+ }
+ return NULL;
+}
+
+extern int qdisc_class_hash_init(struct Qdisc_class_hash *);
+extern void qdisc_class_hash_insert(struct Qdisc_class_hash *, struct Qdisc_class_common *);
+extern void qdisc_class_hash_remove(struct Qdisc_class_hash *, struct Qdisc_class_common *);
+extern void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *);
+extern void qdisc_class_hash_destroy(struct Qdisc_class_hash *);
+
extern void dev_init_scheduler(struct net_device *dev);
extern void dev_shutdown(struct net_device *dev);
extern void dev_activate(struct net_device *dev);
extern void qdisc_reset(struct Qdisc *qdisc);
extern void qdisc_destroy(struct Qdisc *qdisc);
extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
-extern struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops);
+extern struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
+ struct Qdisc_ops *ops);
extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
+ struct netdev_queue *dev_queue,
struct Qdisc_ops *ops, u32 parentid);
+extern void qdisc_calculate_pkt_len(struct sk_buff *skb,
+ struct qdisc_size_table *stab);
extern void tcf_destroy(struct tcf_proto *tp);
-extern void tcf_destroy_chain(struct tcf_proto *fl);
+extern void tcf_destroy_chain(struct tcf_proto **fl);
+
+/* Reset all TX qdiscs of a device. */
+static inline void qdisc_reset_all_tx(struct net_device *dev)
+{
+ unsigned int i;
+ for (i = 0; i < dev->num_tx_queues; i++)
+ qdisc_reset(netdev_get_tx_queue(dev, i)->qdisc);
+}
+
+/* Are all TX queues of the device empty? */
+static inline bool qdisc_all_tx_empty(const struct net_device *dev)
+{
+ unsigned int i;
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
+ const struct Qdisc *q = txq->qdisc;
+
+ if (q->q.qlen)
+ return false;
+ }
+ return true;
+}
+
+/* Are any of the TX qdiscs changing? */
+static inline bool qdisc_tx_changing(struct net_device *dev)
+{
+ unsigned int i;
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
+ if (txq->qdisc != txq->qdisc_sleeping)
+ return true;
+ }
+ return false;
+}
+
+/* Is the device using the noop qdisc on all queues? */
+static inline bool qdisc_tx_is_noop(const struct net_device *dev)
+{
+ unsigned int i;
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
+ if (txq->qdisc != &noop_qdisc)
+ return false;
+ }
+ return true;
+}
+
+static inline unsigned int qdisc_pkt_len(struct sk_buff *skb)
+{
+ return qdisc_skb_cb(skb)->pkt_len;
+}
+
+static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+#ifdef CONFIG_NET_SCHED
+ if (sch->stab)
+ qdisc_calculate_pkt_len(skb, sch->stab);
+#endif
+ return sch->enqueue(skb, sch);
+}
+
+static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch)
+{
+ qdisc_skb_cb(skb)->pkt_len = skb->len;
+ return qdisc_enqueue(skb, sch);
+}
static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff_head *list)
{
__skb_queue_tail(list, skb);
- sch->qstats.backlog += skb->len;
- sch->bstats.bytes += skb->len;
+ sch->qstats.backlog += qdisc_pkt_len(skb);
+ sch->bstats.bytes += qdisc_pkt_len(skb);
sch->bstats.packets++;
return NET_XMIT_SUCCESS;
struct sk_buff *skb = __skb_dequeue(list);
if (likely(skb != NULL))
- sch->qstats.backlog -= skb->len;
+ sch->qstats.backlog -= qdisc_pkt_len(skb);
return skb;
}
struct sk_buff *skb = __skb_dequeue_tail(list);
if (likely(skb != NULL))
- sch->qstats.backlog -= skb->len;
+ sch->qstats.backlog -= qdisc_pkt_len(skb);
return skb;
}
struct sk_buff_head *list)
{
__skb_queue_head(list, skb);
- sch->qstats.backlog += skb->len;
+ sch->qstats.backlog += qdisc_pkt_len(skb);
sch->qstats.requeues++;
return NET_XMIT_SUCCESS;
* We do not know the backlog in bytes of this list, it
* is up to the caller to correct it
*/
- skb_queue_purge(list);
+ __skb_queue_purge(list);
}
static inline void qdisc_reset_queue(struct Qdisc *sch)
struct sk_buff *skb = __qdisc_dequeue_tail(sch, list);
if (likely(skb != NULL)) {
- unsigned int len = skb->len;
+ unsigned int len = qdisc_pkt_len(skb);
kfree_skb(skb);
return len;
}
return NET_XMIT_DROP;
}
+/* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how
+ long it will take to send a packet given its size.
+ */
+static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen)
+{
+ int slot = pktlen + rtab->rate.cell_align + rtab->rate.overhead;
+ if (slot < 0)
+ slot = 0;
+ slot >>= rtab->rate.cell_log;
+ if (slot > 255)
+ return (rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]);
+ return rtab->data[slot];
+}
+
+#ifdef CONFIG_NET_CLS_ACT
+static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask)
+{
+ struct sk_buff *n = skb_clone(skb, gfp_mask);
+
+ if (n) {
+ n->tc_verd = SET_TC_VERD(n->tc_verd, 0);
+ n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
+ n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
+ }
+ return n;
+}
+#endif
+
#endif