|
@@ -34,10 +34,12 @@
|
|
|
#include <net/netlink.h>
|
|
|
#include <net/pkt_sched.h>
|
|
|
|
|
|
-static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
|
|
|
+static int qdisc_notify(struct net *net, struct sk_buff *oskb,
|
|
|
+ struct nlmsghdr *n, u32 clid,
|
|
|
struct Qdisc *old, struct Qdisc *new);
|
|
|
-static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
|
|
|
- struct Qdisc *q, unsigned long cl, int event);
|
|
|
+static int tclass_notify(struct net *net, struct sk_buff *oskb,
|
|
|
+ struct nlmsghdr *n, struct Qdisc *q,
|
|
|
+ unsigned long cl, int event);
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -638,11 +640,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
|
|
|
}
|
|
|
EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
|
|
|
|
|
|
-static void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid,
|
|
|
+static void notify_and_destroy(struct net *net, struct sk_buff *skb,
|
|
|
+ struct nlmsghdr *n, u32 clid,
|
|
|
struct Qdisc *old, struct Qdisc *new)
|
|
|
{
|
|
|
if (new || old)
|
|
|
- qdisc_notify(skb, n, clid, old, new);
|
|
|
+ qdisc_notify(net, skb, n, clid, old, new);
|
|
|
|
|
|
if (old)
|
|
|
qdisc_destroy(old);
|
|
@@ -662,6 +665,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
|
|
|
struct Qdisc *new, struct Qdisc *old)
|
|
|
{
|
|
|
struct Qdisc *q = old;
|
|
|
+ struct net *net = dev_net(dev);
|
|
|
int err = 0;
|
|
|
|
|
|
if (parent == NULL) {
|
|
@@ -698,12 +702,13 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
|
|
|
}
|
|
|
|
|
|
if (!ingress) {
|
|
|
- notify_and_destroy(skb, n, classid, dev->qdisc, new);
|
|
|
+ notify_and_destroy(net, 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);
|
|
|
+ notify_and_destroy(net, skb, n, classid, old, new);
|
|
|
}
|
|
|
|
|
|
if (dev->flags & IFF_UP)
|
|
@@ -721,7 +726,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
|
|
|
err = -ENOENT;
|
|
|
}
|
|
|
if (!err)
|
|
|
- notify_and_destroy(skb, n, classid, old, new);
|
|
|
+ notify_and_destroy(net, skb, n, classid, old, new);
|
|
|
}
|
|
|
return err;
|
|
|
}
|
|
@@ -947,10 +952,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
|
|
|
struct Qdisc *p = NULL;
|
|
|
int err;
|
|
|
|
|
|
- if (!net_eq(net, &init_net))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
|
|
|
+ if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
|
|
|
return -ENODEV;
|
|
|
|
|
|
err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
|
|
@@ -990,7 +992,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
|
|
|
if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0)
|
|
|
return err;
|
|
|
} else {
|
|
|
- qdisc_notify(skb, n, clid, NULL, q);
|
|
|
+ qdisc_notify(net, skb, n, clid, NULL, q);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
@@ -1009,16 +1011,13 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
|
|
|
struct Qdisc *q, *p;
|
|
|
int err;
|
|
|
|
|
|
- if (!net_eq(net, &init_net))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
replay:
|
|
|
/* Reinit, just in case something touches this. */
|
|
|
tcm = NLMSG_DATA(n);
|
|
|
clid = tcm->tcm_parent;
|
|
|
q = p = NULL;
|
|
|
|
|
|
- if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
|
|
|
+ if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
|
|
|
return -ENODEV;
|
|
|
|
|
|
err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
|
|
@@ -1105,7 +1104,7 @@ replay:
|
|
|
return -EINVAL;
|
|
|
err = qdisc_change(q, tca);
|
|
|
if (err == 0)
|
|
|
- qdisc_notify(skb, n, clid, NULL, q);
|
|
|
+ qdisc_notify(net, skb, n, clid, NULL, q);
|
|
|
return err;
|
|
|
|
|
|
create_n_graft:
|
|
@@ -1195,8 +1194,9 @@ nla_put_failure:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
|
|
|
- u32 clid, struct Qdisc *old, struct Qdisc *new)
|
|
|
+static int qdisc_notify(struct net *net, struct sk_buff *oskb,
|
|
|
+ struct nlmsghdr *n, u32 clid,
|
|
|
+ struct Qdisc *old, struct Qdisc *new)
|
|
|
{
|
|
|
struct sk_buff *skb;
|
|
|
u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
|
|
@@ -1215,7 +1215,7 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
|
|
|
}
|
|
|
|
|
|
if (skb->len)
|
|
|
- return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
|
|
|
+ return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
|
|
|
|
|
|
err_out:
|
|
|
kfree_skb(skb);
|
|
@@ -1274,15 +1274,12 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
int s_idx, s_q_idx;
|
|
|
struct net_device *dev;
|
|
|
|
|
|
- if (!net_eq(net, &init_net))
|
|
|
- return 0;
|
|
|
-
|
|
|
s_idx = cb->args[0];
|
|
|
s_q_idx = q_idx = cb->args[1];
|
|
|
|
|
|
rcu_read_lock();
|
|
|
idx = 0;
|
|
|
- for_each_netdev_rcu(&init_net, dev) {
|
|
|
+ for_each_netdev_rcu(net, dev) {
|
|
|
struct netdev_queue *dev_queue;
|
|
|
|
|
|
if (idx < s_idx)
|
|
@@ -1334,10 +1331,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
|
|
|
u32 qid = TC_H_MAJ(clid);
|
|
|
int err;
|
|
|
|
|
|
- if (!net_eq(net, &init_net))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
|
|
|
+ if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
|
|
|
return -ENODEV;
|
|
|
|
|
|
err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
|
|
@@ -1418,10 +1412,10 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
|
|
|
if (cops->delete)
|
|
|
err = cops->delete(q, cl);
|
|
|
if (err == 0)
|
|
|
- tclass_notify(skb, n, q, cl, RTM_DELTCLASS);
|
|
|
+ tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS);
|
|
|
goto out;
|
|
|
case RTM_GETTCLASS:
|
|
|
- err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS);
|
|
|
+ err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS);
|
|
|
goto out;
|
|
|
default:
|
|
|
err = -EINVAL;
|
|
@@ -1434,7 +1428,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
|
|
|
if (cops->change)
|
|
|
err = cops->change(q, clid, pid, tca, &new_cl);
|
|
|
if (err == 0)
|
|
|
- tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS);
|
|
|
+ tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS);
|
|
|
|
|
|
out:
|
|
|
if (cl)
|
|
@@ -1486,8 +1480,9 @@ nla_put_failure:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
|
|
|
- struct Qdisc *q, unsigned long cl, int event)
|
|
|
+static int tclass_notify(struct net *net, struct sk_buff *oskb,
|
|
|
+ struct nlmsghdr *n, struct Qdisc *q,
|
|
|
+ unsigned long cl, int event)
|
|
|
{
|
|
|
struct sk_buff *skb;
|
|
|
u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
|
|
@@ -1501,7 +1496,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
|
|
|
+ return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
|
|
|
}
|
|
|
|
|
|
struct qdisc_dump_args
|
|
@@ -1576,12 +1571,9 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
struct net_device *dev;
|
|
|
int t, s_t;
|
|
|
|
|
|
- if (!net_eq(net, &init_net))
|
|
|
- return 0;
|
|
|
-
|
|
|
if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
|
|
|
return 0;
|
|
|
- if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
|
|
|
+ if ((dev = dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
|
|
|
return 0;
|
|
|
|
|
|
s_t = cb->args[0];
|
|
@@ -1701,15 +1693,55 @@ static const struct file_operations psched_fops = {
|
|
|
.llseek = seq_lseek,
|
|
|
.release = single_release,
|
|
|
};
|
|
|
+
|
|
|
+static int __net_init psched_net_init(struct net *net)
|
|
|
+{
|
|
|
+ struct proc_dir_entry *e;
|
|
|
+
|
|
|
+ e = proc_net_fops_create(net, "psched", 0, &psched_fops);
|
|
|
+ if (e == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void __net_exit psched_net_exit(struct net *net)
|
|
|
+{
|
|
|
+ proc_net_remove(net, "psched");
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+#else
|
|
|
+static int __net_init psched_net_init(struct net *net)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void __net_exit psched_net_exit(struct net *net)
|
|
|
+{
|
|
|
+}
|
|
|
#endif
|
|
|
|
|
|
+static struct pernet_operations psched_net_ops = {
|
|
|
+ .init = psched_net_init,
|
|
|
+ .exit = psched_net_exit,
|
|
|
+};
|
|
|
+
|
|
|
static int __init pktsched_init(void)
|
|
|
{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = register_pernet_subsys(&psched_net_ops);
|
|
|
+ if (err) {
|
|
|
+ printk(KERN_ERR "pktsched_init: "
|
|
|
+ "cannot initialize per netns operations\n");
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
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);
|
|
|
rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);
|