if (dev->flags & IFF_UP)
dev_deactivate(dev);
+ if (new && new->ops->attach) {
+ new->ops->attach(new);
+ num_q = 0;
+ }
+
for (i = 0; i < num_q; i++) {
struct netdev_queue *dev_queue = &dev->rx_queue;
if (new && i > 0)
atomic_inc(&new->refcnt);
- qdisc_destroy(old);
+ if (!ingress)
+ qdisc_destroy(old);
}
- notify_and_destroy(skb, n, classid, dev->qdisc, new);
- if (new)
- atomic_inc(&new->refcnt);
- dev->qdisc = new ? : &noop_qdisc;
+ if (!ingress) {
+ notify_and_destroy(skb, n, classid, dev->qdisc, new);
+ if (new && !new->ops->attach)
+ atomic_inc(&new->refcnt);
+ dev->qdisc = new ? : &noop_qdisc;
+ } else {
+ notify_and_destroy(skb, n, classid, old, new);
+ }
if (dev->flags & IFF_UP)
dev_activate(dev);
static struct Qdisc *
qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
- u32 parent, u32 handle, struct nlattr **tca, int *errp)
+ struct Qdisc *p, u32 parent, u32 handle,
+ struct nlattr **tca, int *errp)
{
int err;
struct nlattr *kind = tca[TCA_KIND];
stab = qdisc_get_stab(tca[TCA_STAB]);
if (IS_ERR(stab)) {
err = PTR_ERR(stab);
- goto err_out3;
+ goto err_out4;
}
sch->stab = stab;
}
if (tca[TCA_RATE]) {
spinlock_t *root_lock;
+ err = -EOPNOTSUPP;
+ if (sch->flags & TCQ_F_MQROOT)
+ goto err_out4;
+
if ((sch->parent != TC_H_ROOT) &&
- !(sch->flags & TCQ_F_INGRESS))
+ !(sch->flags & TCQ_F_INGRESS) &&
+ (!p || !(p->flags & TCQ_F_MQROOT)))
root_lock = qdisc_root_sleeping_lock(sch);
else
root_lock = qdisc_lock(sch);
err = gen_new_estimator(&sch->bstats, &sch->rate_est,
root_lock, tca[TCA_RATE]);
- if (err) {
- /*
- * Any broken qdiscs that would require
- * a ops->reset() here? The qdisc was never
- * in action so it shouldn't be necessary.
- */
- if (ops->destroy)
- ops->destroy(sch);
- goto err_out3;
- }
+ if (err)
+ goto err_out4;
}
qdisc_list_add(sch);
return sch;
}
err_out3:
- qdisc_put_stab(sch->stab);
dev_put(dev);
kfree((char *) sch - sch->padded);
err_out2:
err_out:
*errp = err;
return NULL;
+
+err_out4:
+ /*
+ * Any broken qdiscs that would require a ops->reset() here?
+ * The qdisc was never in action so it shouldn't be necessary.
+ */
+ qdisc_put_stab(sch->stab);
+ if (ops->destroy)
+ ops->destroy(sch);
+ goto err_out3;
}
static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
qdisc_put_stab(sch->stab);
sch->stab = stab;
- if (tca[TCA_RATE])
+ if (tca[TCA_RATE]) {
/* NB: ignores errors from replace_estimator
because change can't be undone. */
+ if (sch->flags & TCQ_F_MQROOT)
+ goto out;
gen_replace_estimator(&sch->bstats, &sch->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
-
+ }
+out:
return 0;
}
struct Qdisc *p = NULL;
int err;
- if (net != &init_net)
+ if (!net_eq(net, &init_net))
return -EINVAL;
if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
struct Qdisc *q, *p;
int err;
- if (net != &init_net)
+ if (!net_eq(net, &init_net))
return -EINVAL;
replay:
if (!(n->nlmsg_flags&NLM_F_CREATE))
return -ENOENT;
if (clid == TC_H_INGRESS)
- q = qdisc_create(dev, &dev->rx_queue,
+ q = qdisc_create(dev, &dev->rx_queue, p,
tcm->tcm_parent, tcm->tcm_parent,
tca, &err);
- else
- q = qdisc_create(dev, netdev_get_tx_queue(dev, 0),
+ else {
+ struct netdev_queue *dev_queue;
+
+ if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue)
+ dev_queue = p->ops->cl_ops->select_queue(p, tcm);
+ else if (p)
+ dev_queue = p->dev_queue;
+ else
+ dev_queue = netdev_get_tx_queue(dev, 0);
+
+ q = qdisc_create(dev, dev_queue, p,
tcm->tcm_parent, tcm->tcm_handle,
tca, &err);
+ }
if (q == NULL) {
if (err == -EAGAIN)
goto replay;
goto nla_put_failure;
if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
- gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 ||
gnet_stats_copy_queue(&d, &q->qstats) < 0)
goto nla_put_failure;
int s_idx, s_q_idx;
struct net_device *dev;
- if (net != &init_net)
+ if (!net_eq(net, &init_net))
return 0;
s_idx = cb->args[0];
s_q_idx = q_idx = cb->args[1];
- read_lock(&dev_base_lock);
+
+ rcu_read_lock();
idx = 0;
- for_each_netdev(&init_net, dev) {
+ for_each_netdev_rcu(&init_net, dev) {
struct netdev_queue *dev_queue;
if (idx < s_idx)
}
done:
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
cb->args[0] = idx;
cb->args[1] = q_idx;
u32 qid = TC_H_MAJ(clid);
int err;
- if (net != &init_net)
+ if (!net_eq(net, &init_net))
return -EINVAL;
if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
tcm = NLMSG_DATA(nlh);
tcm->tcm_family = AF_UNSPEC;
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
tcm->tcm_parent = q->handle;
tcm->tcm_handle = q->handle;
struct net_device *dev;
int t, s_t;
- if (net != &init_net)
+ if (!net_eq(net, &init_net))
return 0;
if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
{
register_qdisc(&pfifo_qdisc_ops);
register_qdisc(&bfifo_qdisc_ops);
+ register_qdisc(&pfifo_head_drop_qdisc_ops);
+ register_qdisc(&mq_qdisc_ops);
proc_net_fops_create(&init_net, "psched", 0, &psched_fops);
rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);