diff options
Diffstat (limited to 'include/net/sch_generic.h')
-rw-r--r-- | include/net/sch_generic.h | 144 |
1 files changed, 134 insertions, 10 deletions
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a87fc0312ed..0a158ff4de1 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -23,6 +23,12 @@ struct qdisc_rate_table int refcnt; }; +enum qdisc_state_t +{ + __QDISC_STATE_RUNNING, + __QDISC_STATE_SCHED, +}; + struct Qdisc { int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev); @@ -36,14 +42,16 @@ struct Qdisc 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); @@ -155,18 +163,86 @@ struct tcf_proto struct tcf_proto_ops *ops; }; +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; +} -extern void qdisc_lock_tree(struct net_device *dev); -extern void qdisc_unlock_tree(struct net_device *dev); +static inline void sch_tree_lock(struct Qdisc *q) +{ + spin_lock_bh(qdisc_root_lock(q)); +} + +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); @@ -174,12 +250,60 @@ extern void dev_deactivate(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 tcf_destroy(struct tcf_proto *tp); 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 int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff_head *list) { @@ -250,7 +374,7 @@ static inline void __qdisc_reset_queue(struct Qdisc *sch, * 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) |