struct net_device *dev;
struct Qdisc *slaves;
struct list_head master_list;
- struct net_device_stats stats;
};
struct teql_sched_data
static int
teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
- struct net_device *dev = sch->dev;
+ struct net_device *dev = qdisc_dev(sch);
struct teql_sched_data *q = qdisc_priv(sch);
if (q->q.qlen < dev->tx_queue_len) {
__skb_queue_tail(&q->q, skb);
- sch->bstats.bytes += skb->len;
+ sch->bstats.bytes += qdisc_pkt_len(skb);
sch->bstats.packets++;
return 0;
}
return NET_XMIT_DROP;
}
-static int
-teql_requeue(struct sk_buff *skb, struct Qdisc* sch)
-{
- struct teql_sched_data *q = qdisc_priv(sch);
-
- __skb_queue_head(&q->q, skb);
- sch->qstats.requeues++;
- return 0;
-}
-
static struct sk_buff *
teql_dequeue(struct Qdisc* sch)
{
struct teql_sched_data *dat = qdisc_priv(sch);
+ struct netdev_queue *dat_queue;
struct sk_buff *skb;
skb = __skb_dequeue(&dat->q);
+ dat_queue = netdev_get_tx_queue(dat->m->dev, 0);
if (skb == NULL) {
- struct net_device *m = dat->m->dev->qdisc->dev;
+ struct net_device *m = qdisc_dev(dat_queue->qdisc);
if (m) {
dat->m->slaves = sch;
netif_wake_queue(m);
}
}
- sch->q.qlen = dat->q.qlen + dat->m->dev->qdisc->q.qlen;
+ sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen;
return skb;
}
+static struct sk_buff *
+teql_peek(struct Qdisc* sch)
+{
+ /* teql is meant to be used as root qdisc */
+ return NULL;
+}
+
static __inline__ void
teql_neigh_release(struct neighbour *n)
{
if (q == master->slaves) {
master->slaves = NEXT_SLAVE(q);
if (q == master->slaves) {
+ struct netdev_queue *txq;
+ spinlock_t *root_lock;
+
+ txq = netdev_get_tx_queue(master->dev, 0);
master->slaves = NULL;
- spin_lock_bh(&master->dev->queue_lock);
- qdisc_reset(master->dev->qdisc);
- spin_unlock_bh(&master->dev->queue_lock);
+
+ root_lock = qdisc_root_sleeping_lock(txq->qdisc);
+ spin_lock_bh(root_lock);
+ qdisc_reset(txq->qdisc);
+ spin_unlock_bh(root_lock);
}
}
skb_queue_purge(&dat->q);
static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt)
{
- struct net_device *dev = sch->dev;
+ struct net_device *dev = qdisc_dev(sch);
struct teql_master *m = (struct teql_master*)sch->ops;
struct teql_sched_data *q = qdisc_priv(sch);
if (m->slaves) {
if (m->dev->flags & IFF_UP) {
- if ((m->dev->flags&IFF_POINTOPOINT && !(dev->flags&IFF_POINTOPOINT))
- || (m->dev->flags&IFF_BROADCAST && !(dev->flags&IFF_BROADCAST))
- || (m->dev->flags&IFF_MULTICAST && !(dev->flags&IFF_MULTICAST))
- || dev->mtu < m->dev->mtu)
+ if ((m->dev->flags & IFF_POINTOPOINT &&
+ !(dev->flags & IFF_POINTOPOINT)) ||
+ (m->dev->flags & IFF_BROADCAST &&
+ !(dev->flags & IFF_BROADCAST)) ||
+ (m->dev->flags & IFF_MULTICAST &&
+ !(dev->flags & IFF_MULTICAST)) ||
+ dev->mtu < m->dev->mtu)
return -EINVAL;
} else {
if (!(dev->flags&IFF_POINTOPOINT))
static int
__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
{
- struct teql_sched_data *q = qdisc_priv(dev->qdisc);
- struct neighbour *mn = skb->dst->neighbour;
+ struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0);
+ struct teql_sched_data *q = qdisc_priv(dev_queue->qdisc);
+ struct neighbour *mn = skb_dst(skb)->neighbour;
struct neighbour *n = q->ncache;
if (mn->tbl == NULL)
static inline int teql_resolve(struct sk_buff *skb,
struct sk_buff *skb_res, struct net_device *dev)
{
- if (dev->qdisc == &noop_qdisc)
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+ if (txq->qdisc == &noop_qdisc)
return -ENODEV;
if (dev->header_ops == NULL ||
- skb->dst == NULL ||
- skb->dst->neighbour == NULL)
+ skb_dst(skb) == NULL ||
+ skb_dst(skb)->neighbour == NULL)
return 0;
return __teql_resolve(skb, skb_res, dev);
}
-static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct teql_master *master = netdev_priv(dev);
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct Qdisc *start, *q;
int busy;
int nores;
- int len = skb->len;
int subq = skb_get_queue_mapping(skb);
struct sk_buff *skb_res = NULL;
goto drop;
do {
- struct net_device *slave = q->dev;
+ struct net_device *slave = qdisc_dev(q);
+ struct netdev_queue *slave_txq = netdev_get_tx_queue(slave, 0);
+ const struct net_device_ops *slave_ops = slave->netdev_ops;
- if (slave->qdisc_sleeping != q)
+ if (slave_txq->qdisc_sleeping != q)
continue;
- if (netif_queue_stopped(slave) ||
- __netif_subqueue_stopped(slave, subq) ||
+ if (__netif_subqueue_stopped(slave, subq) ||
!netif_running(slave)) {
busy = 1;
continue;
switch (teql_resolve(skb, skb_res, slave)) {
case 0:
- if (netif_tx_trylock(slave)) {
- if (!netif_queue_stopped(slave) &&
- !__netif_subqueue_stopped(slave, subq) &&
- slave->hard_start_xmit(skb, slave) == 0) {
- netif_tx_unlock(slave);
+ if (__netif_tx_trylock(slave_txq)) {
+ unsigned int length = qdisc_pkt_len(skb);
+
+ if (!netif_tx_queue_stopped(slave_txq) &&
+ !netif_tx_queue_frozen(slave_txq) &&
+ slave_ops->ndo_start_xmit(skb, slave) == NETDEV_TX_OK) {
+ txq_trans_update(slave_txq);
+ __netif_tx_unlock(slave_txq);
master->slaves = NEXT_SLAVE(q);
netif_wake_queue(dev);
- master->stats.tx_packets++;
- master->stats.tx_bytes += len;
- return 0;
+ txq->tx_packets++;
+ txq->tx_bytes += length;
+ return NETDEV_TX_OK;
}
- netif_tx_unlock(slave);
+ __netif_tx_unlock(slave_txq);
}
if (netif_queue_stopped(dev))
busy = 1;
break;
case 1:
master->slaves = NEXT_SLAVE(q);
- return 0;
+ return NETDEV_TX_OK;
default:
nores = 1;
break;
if (busy) {
netif_stop_queue(dev);
- return 1;
+ return NETDEV_TX_BUSY;
}
- master->stats.tx_errors++;
+ dev->stats.tx_errors++;
drop:
- master->stats.tx_dropped++;
+ txq->tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int teql_master_open(struct net_device *dev)
q = m->slaves;
do {
- struct net_device *slave = q->dev;
+ struct net_device *slave = qdisc_dev(q);
if (slave == NULL)
return -EUNATCH;
return 0;
}
-static struct net_device_stats *teql_master_stats(struct net_device *dev)
-{
- struct teql_master *m = netdev_priv(dev);
- return &m->stats;
-}
-
static int teql_master_mtu(struct net_device *dev, int new_mtu)
{
struct teql_master *m = netdev_priv(dev);
q = m->slaves;
if (q) {
do {
- if (new_mtu > q->dev->mtu)
+ if (new_mtu > qdisc_dev(q)->mtu)
return -EINVAL;
} while ((q=NEXT_SLAVE(q)) != m->slaves);
}
return 0;
}
+static const struct net_device_ops teql_netdev_ops = {
+ .ndo_open = teql_master_open,
+ .ndo_stop = teql_master_close,
+ .ndo_start_xmit = teql_master_xmit,
+ .ndo_change_mtu = teql_master_mtu,
+};
+
static __init void teql_master_setup(struct net_device *dev)
{
struct teql_master *master = netdev_priv(dev);
ops->enqueue = teql_enqueue;
ops->dequeue = teql_dequeue;
- ops->requeue = teql_requeue;
+ ops->peek = teql_peek;
ops->init = teql_qdisc_init;
ops->reset = teql_reset;
ops->destroy = teql_destroy;
ops->owner = THIS_MODULE;
- dev->open = teql_master_open;
- dev->hard_start_xmit = teql_master_xmit;
- dev->stop = teql_master_close;
- dev->get_stats = teql_master_stats;
- dev->change_mtu = teql_master_mtu;
+ dev->netdev_ops = &teql_netdev_ops;
dev->type = ARPHRD_VOID;
dev->mtu = 1500;
dev->tx_queue_len = 100;