Commit b798ab6d authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Hideaki Yoshifuji

[NET]: Update teql scheduler to dynamic net device.

- dynamically allocate and free the network device.
  previously, used static network device.
- support multiple equalizers (default one) via module parameter (max_equalizers)
  previously, limited to one.
parent 81a875bd
......@@ -67,8 +67,9 @@
struct teql_master
{
struct Qdisc_ops qops;
struct net_device dev;
struct net_device *dev;
struct Qdisc *slaves;
struct list_head master_list;
struct net_device_stats stats;
};
......@@ -122,13 +123,13 @@ teql_dequeue(struct Qdisc* sch)
skb = __skb_dequeue(&dat->q);
if (skb == NULL) {
struct net_device *m = dat->m->dev.qdisc->dev;
struct net_device *m = dat->m->dev->qdisc->dev;
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->m->dev->qdisc->q.qlen;
return skb;
}
......@@ -165,9 +166,9 @@ teql_destroy(struct Qdisc* sch)
master->slaves = NEXT_SLAVE(q);
if (q == master->slaves) {
master->slaves = NULL;
spin_lock_bh(&master->dev.queue_lock);
qdisc_reset(master->dev.qdisc);
spin_unlock_bh(&master->dev.queue_lock);
spin_lock_bh(&master->dev->queue_lock);
qdisc_reset(master->dev->qdisc);
spin_unlock_bh(&master->dev->queue_lock);
}
}
skb_queue_purge(&dat->q);
......@@ -185,10 +186,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
struct teql_master *m = (struct teql_master*)sch->ops;
struct teql_sched_data *q = (struct teql_sched_data *)sch->data;
if (dev->hard_header_len > m->dev.hard_header_len)
if (dev->hard_header_len > m->dev->hard_header_len)
return -EINVAL;
if (&m->dev == dev)
if (m->dev == dev)
return -ELOOP;
q->m = m;
......@@ -196,29 +197,29 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
skb_queue_head_init(&q->q);
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_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)
return -EINVAL;
} else {
if (!(dev->flags&IFF_POINTOPOINT))
m->dev.flags &= ~IFF_POINTOPOINT;
m->dev->flags &= ~IFF_POINTOPOINT;
if (!(dev->flags&IFF_BROADCAST))
m->dev.flags &= ~IFF_BROADCAST;
m->dev->flags &= ~IFF_BROADCAST;
if (!(dev->flags&IFF_MULTICAST))
m->dev.flags &= ~IFF_MULTICAST;
if (dev->mtu < m->dev.mtu)
m->dev.mtu = dev->mtu;
m->dev->flags &= ~IFF_MULTICAST;
if (dev->mtu < m->dev->mtu)
m->dev->mtu = dev->mtu;
}
q->next = NEXT_SLAVE(m->slaves);
NEXT_SLAVE(m->slaves) = sch;
} else {
q->next = sch;
m->slaves = sch;
m->dev.mtu = dev->mtu;
m->dev.flags = (m->dev.flags&~FMASK)|(dev->flags&FMASK);
m->dev->mtu = dev->mtu;
m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
}
return 0;
}
......@@ -379,9 +380,9 @@ static int teql_master_open(struct net_device *dev)
flags &= ~IFF_MULTICAST;
} while ((q = NEXT_SLAVE(q)) != m->slaves);
m->dev.mtu = mtu;
m->dev.flags = (m->dev.flags&~FMASK) | flags;
netif_start_queue(&m->dev);
m->dev->mtu = mtu;
m->dev->flags = (m->dev->flags&~FMASK) | flags;
netif_start_queue(m->dev);
return 0;
}
......@@ -417,8 +418,30 @@ static int teql_master_mtu(struct net_device *dev, int new_mtu)
return 0;
}
static int teql_master_init(struct net_device *dev)
static __init int teql_master_init(struct net_device *dev)
{
struct teql_master *master = dev->priv;
struct Qdisc_ops *ops = &master->qops;
master->dev = dev;
strlcpy(ops->id, dev->name, IFNAMSIZ);
ops->priv_size = sizeof(struct teql_sched_data);
ops->enqueue = teql_enqueue;
ops->dequeue = teql_dequeue;
ops->requeue = teql_requeue;
ops->init = teql_qdisc_init;
ops->reset = teql_reset;
ops->destroy = teql_destroy;
ops->owner = THIS_MODULE;
return register_qdisc(ops);
}
static __init void teql_master_setup(struct net_device *dev)
{
dev->init = teql_master_init;
dev->open = teql_master_open;
dev->hard_start_xmit = teql_master_xmit;
dev->stop = teql_master_close;
......@@ -429,62 +452,58 @@ static int teql_master_init(struct net_device *dev)
dev->tx_queue_len = 100;
dev->flags = IFF_NOARP;
dev->hard_header_len = LL_MAX_HEADER;
return 0;
SET_MODULE_OWNER(dev);
}
static struct teql_master the_master = {
{
.next = NULL,
.cl_ops = NULL,
.id = "",
.priv_size = sizeof(struct teql_sched_data),
.enqueue = teql_enqueue,
.dequeue = teql_dequeue,
.requeue = teql_requeue,
.drop = NULL,
.init = teql_qdisc_init,
.reset = teql_reset,
.destroy = teql_destroy,
.dump = NULL,
.owner = THIS_MODULE,
},};
#ifdef MODULE
int init_module(void)
#else
static LIST_HEAD(master_dev_list);
static spinlock_t master_dev_lock = SPIN_LOCK_UNLOCKED;
static int max_equalizers = 1;
MODULE_PARM(max_equalizers, "i");
MODULE_PARM_DESC(max_equalizers, "Max number of link equalizers");
int __init teql_init(void)
#endif
{
int err;
int i;
int err = 0;
rtnl_lock();
for (i = 0; i < max_equalizers; i++) {
struct net_device *dev;
struct teql_master *master;
the_master.dev.priv = (void*)&the_master;
err = dev_alloc_name(&the_master.dev, "teql%d");
if (err < 0)
return err;
memcpy(the_master.qops.id, the_master.dev.name, IFNAMSIZ);
the_master.dev.init = teql_master_init;
SET_MODULE_OWNER(&the_master.dev);
err = register_netdevice(&the_master.dev);
if (err == 0) {
err = register_qdisc(&the_master.qops);
if (err)
unregister_netdevice(&the_master.dev);
dev = alloc_netdev(sizeof(struct teql_master),
"teql%d", teql_master_setup);
if (!dev)
return -ENOMEM;
if ((err = register_netdev(dev)))
goto out;
master = dev->priv;
spin_lock(&master_dev_lock);
list_add_tail(&master->master_list, &master_dev_list);
spin_unlock(&master_dev_lock);
}
rtnl_unlock();
out:
return err;
}
#ifdef MODULE
void cleanup_module(void)
static void __exit teql_exit(void)
{
rtnl_lock();
unregister_qdisc(&the_master.qops);
unregister_netdevice(&the_master.dev);
rtnl_unlock();
struct teql_master *master, *nxt;
spin_lock(&master_dev_lock);
list_for_each_entry_safe(master, nxt, &master_dev_list, master_list) {
list_del(&master->master_list);
unregister_qdisc(&master->qops);
unregister_netdev(master->dev);
kfree(master->dev);
}
spin_unlock(&master_dev_lock);
}
#endif
module_init(teql_init);
module_exit(teql_exit);
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment