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 @@ ...@@ -67,8 +67,9 @@
struct teql_master struct teql_master
{ {
struct Qdisc_ops qops; struct Qdisc_ops qops;
struct net_device dev; struct net_device *dev;
struct Qdisc *slaves; struct Qdisc *slaves;
struct list_head master_list;
struct net_device_stats stats; struct net_device_stats stats;
}; };
...@@ -122,13 +123,13 @@ teql_dequeue(struct Qdisc* sch) ...@@ -122,13 +123,13 @@ teql_dequeue(struct Qdisc* sch)
skb = __skb_dequeue(&dat->q); skb = __skb_dequeue(&dat->q);
if (skb == NULL) { if (skb == NULL) {
struct net_device *m = dat->m->dev.qdisc->dev; struct net_device *m = dat->m->dev->qdisc->dev;
if (m) { if (m) {
dat->m->slaves = sch; dat->m->slaves = sch;
netif_wake_queue(m); 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; return skb;
} }
...@@ -165,9 +166,9 @@ teql_destroy(struct Qdisc* sch) ...@@ -165,9 +166,9 @@ teql_destroy(struct Qdisc* sch)
master->slaves = NEXT_SLAVE(q); master->slaves = NEXT_SLAVE(q);
if (q == master->slaves) { if (q == master->slaves) {
master->slaves = NULL; master->slaves = NULL;
spin_lock_bh(&master->dev.queue_lock); spin_lock_bh(&master->dev->queue_lock);
qdisc_reset(master->dev.qdisc); qdisc_reset(master->dev->qdisc);
spin_unlock_bh(&master->dev.queue_lock); spin_unlock_bh(&master->dev->queue_lock);
} }
} }
skb_queue_purge(&dat->q); skb_queue_purge(&dat->q);
...@@ -185,10 +186,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -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_master *m = (struct teql_master*)sch->ops;
struct teql_sched_data *q = (struct teql_sched_data *)sch->data; 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; return -EINVAL;
if (&m->dev == dev) if (m->dev == dev)
return -ELOOP; return -ELOOP;
q->m = m; q->m = m;
...@@ -196,29 +197,29 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -196,29 +197,29 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
skb_queue_head_init(&q->q); skb_queue_head_init(&q->q);
if (m->slaves) { if (m->slaves) {
if (m->dev.flags & IFF_UP) { if (m->dev->flags & IFF_UP) {
if ((m->dev.flags&IFF_POINTOPOINT && !(dev->flags&IFF_POINTOPOINT)) if ((m->dev->flags&IFF_POINTOPOINT && !(dev->flags&IFF_POINTOPOINT))
|| (m->dev.flags&IFF_BROADCAST && !(dev->flags&IFF_BROADCAST)) || (m->dev->flags&IFF_BROADCAST && !(dev->flags&IFF_BROADCAST))
|| (m->dev.flags&IFF_MULTICAST && !(dev->flags&IFF_MULTICAST)) || (m->dev->flags&IFF_MULTICAST && !(dev->flags&IFF_MULTICAST))
|| dev->mtu < m->dev.mtu) || dev->mtu < m->dev->mtu)
return -EINVAL; return -EINVAL;
} else { } else {
if (!(dev->flags&IFF_POINTOPOINT)) if (!(dev->flags&IFF_POINTOPOINT))
m->dev.flags &= ~IFF_POINTOPOINT; m->dev->flags &= ~IFF_POINTOPOINT;
if (!(dev->flags&IFF_BROADCAST)) if (!(dev->flags&IFF_BROADCAST))
m->dev.flags &= ~IFF_BROADCAST; m->dev->flags &= ~IFF_BROADCAST;
if (!(dev->flags&IFF_MULTICAST)) if (!(dev->flags&IFF_MULTICAST))
m->dev.flags &= ~IFF_MULTICAST; m->dev->flags &= ~IFF_MULTICAST;
if (dev->mtu < m->dev.mtu) if (dev->mtu < m->dev->mtu)
m->dev.mtu = dev->mtu; m->dev->mtu = dev->mtu;
} }
q->next = NEXT_SLAVE(m->slaves); q->next = NEXT_SLAVE(m->slaves);
NEXT_SLAVE(m->slaves) = sch; NEXT_SLAVE(m->slaves) = sch;
} else { } else {
q->next = sch; q->next = sch;
m->slaves = sch; m->slaves = sch;
m->dev.mtu = dev->mtu; m->dev->mtu = dev->mtu;
m->dev.flags = (m->dev.flags&~FMASK)|(dev->flags&FMASK); m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
} }
return 0; return 0;
} }
...@@ -379,9 +380,9 @@ static int teql_master_open(struct net_device *dev) ...@@ -379,9 +380,9 @@ static int teql_master_open(struct net_device *dev)
flags &= ~IFF_MULTICAST; flags &= ~IFF_MULTICAST;
} while ((q = NEXT_SLAVE(q)) != m->slaves); } while ((q = NEXT_SLAVE(q)) != m->slaves);
m->dev.mtu = mtu; m->dev->mtu = mtu;
m->dev.flags = (m->dev.flags&~FMASK) | flags; m->dev->flags = (m->dev->flags&~FMASK) | flags;
netif_start_queue(&m->dev); netif_start_queue(m->dev);
return 0; return 0;
} }
...@@ -417,8 +418,30 @@ static int teql_master_mtu(struct net_device *dev, int new_mtu) ...@@ -417,8 +418,30 @@ static int teql_master_mtu(struct net_device *dev, int new_mtu)
return 0; 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->open = teql_master_open;
dev->hard_start_xmit = teql_master_xmit; dev->hard_start_xmit = teql_master_xmit;
dev->stop = teql_master_close; dev->stop = teql_master_close;
...@@ -429,62 +452,58 @@ static int teql_master_init(struct net_device *dev) ...@@ -429,62 +452,58 @@ static int teql_master_init(struct net_device *dev)
dev->tx_queue_len = 100; dev->tx_queue_len = 100;
dev->flags = IFF_NOARP; dev->flags = IFF_NOARP;
dev->hard_header_len = LL_MAX_HEADER; dev->hard_header_len = LL_MAX_HEADER;
return 0; SET_MODULE_OWNER(dev);
} }
static struct teql_master the_master = { static LIST_HEAD(master_dev_list);
{ static spinlock_t master_dev_lock = SPIN_LOCK_UNLOCKED;
.next = NULL, static int max_equalizers = 1;
.cl_ops = NULL, MODULE_PARM(max_equalizers, "i");
.id = "", MODULE_PARM_DESC(max_equalizers, "Max number of link equalizers");
.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
int __init teql_init(void) 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; dev = alloc_netdev(sizeof(struct teql_master),
err = dev_alloc_name(&the_master.dev, "teql%d"); "teql%d", teql_master_setup);
if (err < 0) if (!dev)
return err; return -ENOMEM;
memcpy(the_master.qops.id, the_master.dev.name, IFNAMSIZ);
the_master.dev.init = teql_master_init; if ((err = register_netdev(dev)))
goto out;
SET_MODULE_OWNER(&the_master.dev);
err = register_netdevice(&the_master.dev); master = dev->priv;
if (err == 0) { spin_lock(&master_dev_lock);
err = register_qdisc(&the_master.qops); list_add_tail(&master->master_list, &master_dev_list);
if (err) spin_unlock(&master_dev_lock);
unregister_netdevice(&the_master.dev);
} }
rtnl_unlock(); out:
return err; return err;
} }
#ifdef MODULE static void __exit teql_exit(void)
void cleanup_module(void)
{ {
rtnl_lock(); struct teql_master *master, *nxt;
unregister_qdisc(&the_master.qops);
unregister_netdevice(&the_master.dev); spin_lock(&master_dev_lock);
rtnl_unlock(); 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"); 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