aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r--net/sched/sch_api.c159
1 files changed, 103 insertions, 56 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 75fd1c672c61..408eea7086aa 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -28,16 +28,19 @@
28#include <linux/list.h> 28#include <linux/list.h>
29#include <linux/hrtimer.h> 29#include <linux/hrtimer.h>
30#include <linux/lockdep.h> 30#include <linux/lockdep.h>
31#include <linux/slab.h>
31 32
32#include <net/net_namespace.h> 33#include <net/net_namespace.h>
33#include <net/sock.h> 34#include <net/sock.h>
34#include <net/netlink.h> 35#include <net/netlink.h>
35#include <net/pkt_sched.h> 36#include <net/pkt_sched.h>
36 37
37static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, 38static int qdisc_notify(struct net *net, struct sk_buff *oskb,
39 struct nlmsghdr *n, u32 clid,
38 struct Qdisc *old, struct Qdisc *new); 40 struct Qdisc *old, struct Qdisc *new);
39static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, 41static int tclass_notify(struct net *net, struct sk_buff *oskb,
40 struct Qdisc *q, unsigned long cl, int event); 42 struct nlmsghdr *n, struct Qdisc *q,
43 unsigned long cl, int event);
41 44
42/* 45/*
43 46
@@ -147,22 +150,34 @@ int register_qdisc(struct Qdisc_ops *qops)
147 if (qops->enqueue == NULL) 150 if (qops->enqueue == NULL)
148 qops->enqueue = noop_qdisc_ops.enqueue; 151 qops->enqueue = noop_qdisc_ops.enqueue;
149 if (qops->peek == NULL) { 152 if (qops->peek == NULL) {
150 if (qops->dequeue == NULL) { 153 if (qops->dequeue == NULL)
151 qops->peek = noop_qdisc_ops.peek; 154 qops->peek = noop_qdisc_ops.peek;
152 } else { 155 else
153 rc = -EINVAL; 156 goto out_einval;
154 goto out;
155 }
156 } 157 }
157 if (qops->dequeue == NULL) 158 if (qops->dequeue == NULL)
158 qops->dequeue = noop_qdisc_ops.dequeue; 159 qops->dequeue = noop_qdisc_ops.dequeue;
159 160
161 if (qops->cl_ops) {
162 const struct Qdisc_class_ops *cops = qops->cl_ops;
163
164 if (!(cops->get && cops->put && cops->walk && cops->leaf))
165 goto out_einval;
166
167 if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
168 goto out_einval;
169 }
170
160 qops->next = NULL; 171 qops->next = NULL;
161 *qp = qops; 172 *qp = qops;
162 rc = 0; 173 rc = 0;
163out: 174out:
164 write_unlock(&qdisc_mod_lock); 175 write_unlock(&qdisc_mod_lock);
165 return rc; 176 return rc;
177
178out_einval:
179 rc = -EINVAL;
180 goto out;
166} 181}
167EXPORT_SYMBOL(register_qdisc); 182EXPORT_SYMBOL(register_qdisc);
168 183
@@ -638,11 +653,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
638} 653}
639EXPORT_SYMBOL(qdisc_tree_decrease_qlen); 654EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
640 655
641static void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid, 656static void notify_and_destroy(struct net *net, struct sk_buff *skb,
657 struct nlmsghdr *n, u32 clid,
642 struct Qdisc *old, struct Qdisc *new) 658 struct Qdisc *old, struct Qdisc *new)
643{ 659{
644 if (new || old) 660 if (new || old)
645 qdisc_notify(skb, n, clid, old, new); 661 qdisc_notify(net, skb, n, clid, old, new);
646 662
647 if (old) 663 if (old)
648 qdisc_destroy(old); 664 qdisc_destroy(old);
@@ -662,6 +678,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
662 struct Qdisc *new, struct Qdisc *old) 678 struct Qdisc *new, struct Qdisc *old)
663{ 679{
664 struct Qdisc *q = old; 680 struct Qdisc *q = old;
681 struct net *net = dev_net(dev);
665 int err = 0; 682 int err = 0;
666 683
667 if (parent == NULL) { 684 if (parent == NULL) {
@@ -698,12 +715,13 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
698 } 715 }
699 716
700 if (!ingress) { 717 if (!ingress) {
701 notify_and_destroy(skb, n, classid, dev->qdisc, new); 718 notify_and_destroy(net, skb, n, classid,
719 dev->qdisc, new);
702 if (new && !new->ops->attach) 720 if (new && !new->ops->attach)
703 atomic_inc(&new->refcnt); 721 atomic_inc(&new->refcnt);
704 dev->qdisc = new ? : &noop_qdisc; 722 dev->qdisc = new ? : &noop_qdisc;
705 } else { 723 } else {
706 notify_and_destroy(skb, n, classid, old, new); 724 notify_and_destroy(net, skb, n, classid, old, new);
707 } 725 }
708 726
709 if (dev->flags & IFF_UP) 727 if (dev->flags & IFF_UP)
@@ -721,7 +739,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
721 err = -ENOENT; 739 err = -ENOENT;
722 } 740 }
723 if (!err) 741 if (!err)
724 notify_and_destroy(skb, n, classid, old, new); 742 notify_and_destroy(net, skb, n, classid, old, new);
725 } 743 }
726 return err; 744 return err;
727} 745}
@@ -947,10 +965,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
947 struct Qdisc *p = NULL; 965 struct Qdisc *p = NULL;
948 int err; 966 int err;
949 967
950 if (!net_eq(net, &init_net)) 968 if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
951 return -EINVAL;
952
953 if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
954 return -ENODEV; 969 return -ENODEV;
955 970
956 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 971 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
@@ -990,7 +1005,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
990 if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0) 1005 if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0)
991 return err; 1006 return err;
992 } else { 1007 } else {
993 qdisc_notify(skb, n, clid, NULL, q); 1008 qdisc_notify(net, skb, n, clid, NULL, q);
994 } 1009 }
995 return 0; 1010 return 0;
996} 1011}
@@ -1009,16 +1024,13 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1009 struct Qdisc *q, *p; 1024 struct Qdisc *q, *p;
1010 int err; 1025 int err;
1011 1026
1012 if (!net_eq(net, &init_net))
1013 return -EINVAL;
1014
1015replay: 1027replay:
1016 /* Reinit, just in case something touches this. */ 1028 /* Reinit, just in case something touches this. */
1017 tcm = NLMSG_DATA(n); 1029 tcm = NLMSG_DATA(n);
1018 clid = tcm->tcm_parent; 1030 clid = tcm->tcm_parent;
1019 q = p = NULL; 1031 q = p = NULL;
1020 1032
1021 if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) 1033 if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
1022 return -ENODEV; 1034 return -ENODEV;
1023 1035
1024 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 1036 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
@@ -1105,7 +1117,7 @@ replay:
1105 return -EINVAL; 1117 return -EINVAL;
1106 err = qdisc_change(q, tca); 1118 err = qdisc_change(q, tca);
1107 if (err == 0) 1119 if (err == 0)
1108 qdisc_notify(skb, n, clid, NULL, q); 1120 qdisc_notify(net, skb, n, clid, NULL, q);
1109 return err; 1121 return err;
1110 1122
1111create_n_graft: 1123create_n_graft:
@@ -1195,8 +1207,14 @@ nla_put_failure:
1195 return -1; 1207 return -1;
1196} 1208}
1197 1209
1198static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, 1210static bool tc_qdisc_dump_ignore(struct Qdisc *q)
1199 u32 clid, struct Qdisc *old, struct Qdisc *new) 1211{
1212 return (q->flags & TCQ_F_BUILTIN) ? true : false;
1213}
1214
1215static int qdisc_notify(struct net *net, struct sk_buff *oskb,
1216 struct nlmsghdr *n, u32 clid,
1217 struct Qdisc *old, struct Qdisc *new)
1200{ 1218{
1201 struct sk_buff *skb; 1219 struct sk_buff *skb;
1202 u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; 1220 u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
@@ -1205,28 +1223,23 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
1205 if (!skb) 1223 if (!skb)
1206 return -ENOBUFS; 1224 return -ENOBUFS;
1207 1225
1208 if (old && old->handle) { 1226 if (old && !tc_qdisc_dump_ignore(old)) {
1209 if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0) 1227 if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0)
1210 goto err_out; 1228 goto err_out;
1211 } 1229 }
1212 if (new) { 1230 if (new && !tc_qdisc_dump_ignore(new)) {
1213 if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) 1231 if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
1214 goto err_out; 1232 goto err_out;
1215 } 1233 }
1216 1234
1217 if (skb->len) 1235 if (skb->len)
1218 return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); 1236 return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
1219 1237
1220err_out: 1238err_out:
1221 kfree_skb(skb); 1239 kfree_skb(skb);
1222 return -EINVAL; 1240 return -EINVAL;
1223} 1241}
1224 1242
1225static bool tc_qdisc_dump_ignore(struct Qdisc *q)
1226{
1227 return (q->flags & TCQ_F_BUILTIN) ? true : false;
1228}
1229
1230static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, 1243static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
1231 struct netlink_callback *cb, 1244 struct netlink_callback *cb,
1232 int *q_idx_p, int s_q_idx) 1245 int *q_idx_p, int s_q_idx)
@@ -1274,15 +1287,12 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
1274 int s_idx, s_q_idx; 1287 int s_idx, s_q_idx;
1275 struct net_device *dev; 1288 struct net_device *dev;
1276 1289
1277 if (!net_eq(net, &init_net))
1278 return 0;
1279
1280 s_idx = cb->args[0]; 1290 s_idx = cb->args[0];
1281 s_q_idx = q_idx = cb->args[1]; 1291 s_q_idx = q_idx = cb->args[1];
1282 1292
1283 rcu_read_lock(); 1293 rcu_read_lock();
1284 idx = 0; 1294 idx = 0;
1285 for_each_netdev_rcu(&init_net, dev) { 1295 for_each_netdev_rcu(net, dev) {
1286 struct netdev_queue *dev_queue; 1296 struct netdev_queue *dev_queue;
1287 1297
1288 if (idx < s_idx) 1298 if (idx < s_idx)
@@ -1334,10 +1344,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1334 u32 qid = TC_H_MAJ(clid); 1344 u32 qid = TC_H_MAJ(clid);
1335 int err; 1345 int err;
1336 1346
1337 if (!net_eq(net, &init_net)) 1347 if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
1338 return -EINVAL;
1339
1340 if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
1341 return -ENODEV; 1348 return -ENODEV;
1342 1349
1343 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); 1350 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
@@ -1418,10 +1425,10 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1418 if (cops->delete) 1425 if (cops->delete)
1419 err = cops->delete(q, cl); 1426 err = cops->delete(q, cl);
1420 if (err == 0) 1427 if (err == 0)
1421 tclass_notify(skb, n, q, cl, RTM_DELTCLASS); 1428 tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS);
1422 goto out; 1429 goto out;
1423 case RTM_GETTCLASS: 1430 case RTM_GETTCLASS:
1424 err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS); 1431 err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS);
1425 goto out; 1432 goto out;
1426 default: 1433 default:
1427 err = -EINVAL; 1434 err = -EINVAL;
@@ -1434,7 +1441,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1434 if (cops->change) 1441 if (cops->change)
1435 err = cops->change(q, clid, pid, tca, &new_cl); 1442 err = cops->change(q, clid, pid, tca, &new_cl);
1436 if (err == 0) 1443 if (err == 0)
1437 tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS); 1444 tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS);
1438 1445
1439out: 1446out:
1440 if (cl) 1447 if (cl)
@@ -1486,8 +1493,9 @@ nla_put_failure:
1486 return -1; 1493 return -1;
1487} 1494}
1488 1495
1489static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, 1496static int tclass_notify(struct net *net, struct sk_buff *oskb,
1490 struct Qdisc *q, unsigned long cl, int event) 1497 struct nlmsghdr *n, struct Qdisc *q,
1498 unsigned long cl, int event)
1491{ 1499{
1492 struct sk_buff *skb; 1500 struct sk_buff *skb;
1493 u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; 1501 u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
@@ -1501,7 +1509,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
1501 return -EINVAL; 1509 return -EINVAL;
1502 } 1510 }
1503 1511
1504 return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); 1512 return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
1505} 1513}
1506 1514
1507struct qdisc_dump_args 1515struct qdisc_dump_args
@@ -1576,12 +1584,9 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
1576 struct net_device *dev; 1584 struct net_device *dev;
1577 int t, s_t; 1585 int t, s_t;
1578 1586
1579 if (!net_eq(net, &init_net))
1580 return 0;
1581
1582 if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) 1587 if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
1583 return 0; 1588 return 0;
1584 if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) 1589 if ((dev = dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
1585 return 0; 1590 return 0;
1586 1591
1587 s_t = cb->args[0]; 1592 s_t = cb->args[0];
@@ -1644,9 +1649,12 @@ reclassify:
1644 tp = otp; 1649 tp = otp;
1645 1650
1646 if (verd++ >= MAX_REC_LOOP) { 1651 if (verd++ >= MAX_REC_LOOP) {
1647 printk("rule prio %u protocol %02x reclassify loop, " 1652 if (net_ratelimit())
1648 "packet dropped\n", 1653 printk(KERN_NOTICE
1649 tp->prio&0xffff, ntohs(tp->protocol)); 1654 "%s: packet reclassify loop"
1655 " rule prio %u protocol %02x\n",
1656 tp->q->ops->id,
1657 tp->prio & 0xffff, ntohs(tp->protocol));
1650 return TC_ACT_SHOT; 1658 return TC_ACT_SHOT;
1651 } 1659 }
1652 skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); 1660 skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
@@ -1691,7 +1699,7 @@ static int psched_show(struct seq_file *seq, void *v)
1691 1699
1692static int psched_open(struct inode *inode, struct file *file) 1700static int psched_open(struct inode *inode, struct file *file)
1693{ 1701{
1694 return single_open(file, psched_show, PDE(inode)->data); 1702 return single_open(file, psched_show, NULL);
1695} 1703}
1696 1704
1697static const struct file_operations psched_fops = { 1705static const struct file_operations psched_fops = {
@@ -1701,14 +1709,53 @@ static const struct file_operations psched_fops = {
1701 .llseek = seq_lseek, 1709 .llseek = seq_lseek,
1702 .release = single_release, 1710 .release = single_release,
1703}; 1711};
1712
1713static int __net_init psched_net_init(struct net *net)
1714{
1715 struct proc_dir_entry *e;
1716
1717 e = proc_net_fops_create(net, "psched", 0, &psched_fops);
1718 if (e == NULL)
1719 return -ENOMEM;
1720
1721 return 0;
1722}
1723
1724static void __net_exit psched_net_exit(struct net *net)
1725{
1726 proc_net_remove(net, "psched");
1727}
1728#else
1729static int __net_init psched_net_init(struct net *net)
1730{
1731 return 0;
1732}
1733
1734static void __net_exit psched_net_exit(struct net *net)
1735{
1736}
1704#endif 1737#endif
1705 1738
1739static struct pernet_operations psched_net_ops = {
1740 .init = psched_net_init,
1741 .exit = psched_net_exit,
1742};
1743
1706static int __init pktsched_init(void) 1744static int __init pktsched_init(void)
1707{ 1745{
1746 int err;
1747
1748 err = register_pernet_subsys(&psched_net_ops);
1749 if (err) {
1750 printk(KERN_ERR "pktsched_init: "
1751 "cannot initialize per netns operations\n");
1752 return err;
1753 }
1754
1708 register_qdisc(&pfifo_qdisc_ops); 1755 register_qdisc(&pfifo_qdisc_ops);
1709 register_qdisc(&bfifo_qdisc_ops); 1756 register_qdisc(&bfifo_qdisc_ops);
1757 register_qdisc(&pfifo_head_drop_qdisc_ops);
1710 register_qdisc(&mq_qdisc_ops); 1758 register_qdisc(&mq_qdisc_ops);
1711 proc_net_fops_create(&init_net, "psched", 0, &psched_fops);
1712 1759
1713 rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); 1760 rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);
1714 rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL); 1761 rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);