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.c227
1 files changed, 96 insertions, 131 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index ecc988af4a9a..8699e7006d80 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -27,14 +27,15 @@
27#include <linux/interrupt.h> 27#include <linux/interrupt.h>
28#include <linux/netdevice.h> 28#include <linux/netdevice.h>
29#include <linux/skbuff.h> 29#include <linux/skbuff.h>
30#include <linux/rtnetlink.h>
31#include <linux/init.h> 30#include <linux/init.h>
32#include <linux/proc_fs.h> 31#include <linux/proc_fs.h>
33#include <linux/seq_file.h> 32#include <linux/seq_file.h>
34#include <linux/kmod.h> 33#include <linux/kmod.h>
35#include <linux/list.h> 34#include <linux/list.h>
36#include <linux/bitops.h> 35#include <linux/bitops.h>
36#include <linux/hrtimer.h>
37 37
38#include <net/netlink.h>
38#include <net/sock.h> 39#include <net/sock.h>
39#include <net/pkt_sched.h> 40#include <net/pkt_sched.h>
40 41
@@ -190,7 +191,7 @@ int unregister_qdisc(struct Qdisc_ops *qops)
190 (root qdisc, all its children, children of children etc.) 191 (root qdisc, all its children, children of children etc.)
191 */ 192 */
192 193
193static struct Qdisc *__qdisc_lookup(struct net_device *dev, u32 handle) 194struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
194{ 195{
195 struct Qdisc *q; 196 struct Qdisc *q;
196 197
@@ -201,16 +202,6 @@ static struct Qdisc *__qdisc_lookup(struct net_device *dev, u32 handle)
201 return NULL; 202 return NULL;
202} 203}
203 204
204struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
205{
206 struct Qdisc *q;
207
208 read_lock(&qdisc_tree_lock);
209 q = __qdisc_lookup(dev, handle);
210 read_unlock(&qdisc_tree_lock);
211 return q;
212}
213
214static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) 205static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
215{ 206{
216 unsigned long cl; 207 unsigned long cl;
@@ -291,6 +282,48 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab)
291 } 282 }
292} 283}
293 284
285static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
286{
287 struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
288 timer);
289 struct net_device *dev = wd->qdisc->dev;
290
291 wd->qdisc->flags &= ~TCQ_F_THROTTLED;
292 smp_wmb();
293 if (spin_trylock(&dev->queue_lock)) {
294 qdisc_run(dev);
295 spin_unlock(&dev->queue_lock);
296 } else
297 netif_schedule(dev);
298
299 return HRTIMER_NORESTART;
300}
301
302void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc)
303{
304 hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
305 wd->timer.function = qdisc_watchdog;
306 wd->qdisc = qdisc;
307}
308EXPORT_SYMBOL(qdisc_watchdog_init);
309
310void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires)
311{
312 ktime_t time;
313
314 wd->qdisc->flags |= TCQ_F_THROTTLED;
315 time = ktime_set(0, 0);
316 time = ktime_add_ns(time, PSCHED_US2NS(expires));
317 hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS);
318}
319EXPORT_SYMBOL(qdisc_watchdog_schedule);
320
321void qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
322{
323 hrtimer_cancel(&wd->timer);
324 wd->qdisc->flags &= ~TCQ_F_THROTTLED;
325}
326EXPORT_SYMBOL(qdisc_watchdog_cancel);
294 327
295/* Allocate an unique handle from space managed by kernel */ 328/* Allocate an unique handle from space managed by kernel */
296 329
@@ -362,7 +395,7 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
362 if (n == 0) 395 if (n == 0)
363 return; 396 return;
364 while ((parentid = sch->parent)) { 397 while ((parentid = sch->parent)) {
365 sch = __qdisc_lookup(sch->dev, TC_H_MAJ(parentid)); 398 sch = qdisc_lookup(sch->dev, TC_H_MAJ(parentid));
366 cops = sch->ops->cl_ops; 399 cops = sch->ops->cl_ops;
367 if (cops->qlen_notify) { 400 if (cops->qlen_notify) {
368 cl = cops->get(sch, parentid); 401 cl = cops->get(sch, parentid);
@@ -467,12 +500,16 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
467 500
468 if (handle == TC_H_INGRESS) { 501 if (handle == TC_H_INGRESS) {
469 sch->flags |= TCQ_F_INGRESS; 502 sch->flags |= TCQ_F_INGRESS;
503 sch->stats_lock = &dev->ingress_lock;
470 handle = TC_H_MAKE(TC_H_INGRESS, 0); 504 handle = TC_H_MAKE(TC_H_INGRESS, 0);
471 } else if (handle == 0) { 505 } else {
472 handle = qdisc_alloc_handle(dev); 506 sch->stats_lock = &dev->queue_lock;
473 err = -ENOMEM; 507 if (handle == 0) {
474 if (handle == 0) 508 handle = qdisc_alloc_handle(dev);
475 goto err_out3; 509 err = -ENOMEM;
510 if (handle == 0)
511 goto err_out3;
512 }
476 } 513 }
477 514
478 sch->handle = handle; 515 sch->handle = handle;
@@ -621,9 +658,9 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
621 return err; 658 return err;
622 if (q) { 659 if (q) {
623 qdisc_notify(skb, n, clid, q, NULL); 660 qdisc_notify(skb, n, clid, q, NULL);
624 spin_lock_bh(&dev->queue_lock); 661 qdisc_lock_tree(dev);
625 qdisc_destroy(q); 662 qdisc_destroy(q);
626 spin_unlock_bh(&dev->queue_lock); 663 qdisc_unlock_tree(dev);
627 } 664 }
628 } else { 665 } else {
629 qdisc_notify(skb, n, clid, NULL, q); 666 qdisc_notify(skb, n, clid, NULL, q);
@@ -756,17 +793,17 @@ graft:
756 err = qdisc_graft(dev, p, clid, q, &old_q); 793 err = qdisc_graft(dev, p, clid, q, &old_q);
757 if (err) { 794 if (err) {
758 if (q) { 795 if (q) {
759 spin_lock_bh(&dev->queue_lock); 796 qdisc_lock_tree(dev);
760 qdisc_destroy(q); 797 qdisc_destroy(q);
761 spin_unlock_bh(&dev->queue_lock); 798 qdisc_unlock_tree(dev);
762 } 799 }
763 return err; 800 return err;
764 } 801 }
765 qdisc_notify(skb, n, clid, old_q, q); 802 qdisc_notify(skb, n, clid, old_q, q);
766 if (old_q) { 803 if (old_q) {
767 spin_lock_bh(&dev->queue_lock); 804 qdisc_lock_tree(dev);
768 qdisc_destroy(old_q); 805 qdisc_destroy(old_q);
769 spin_unlock_bh(&dev->queue_lock); 806 qdisc_unlock_tree(dev);
770 } 807 }
771 } 808 }
772 return 0; 809 return 0;
@@ -777,7 +814,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
777{ 814{
778 struct tcmsg *tcm; 815 struct tcmsg *tcm;
779 struct nlmsghdr *nlh; 816 struct nlmsghdr *nlh;
780 unsigned char *b = skb->tail; 817 unsigned char *b = skb_tail_pointer(skb);
781 struct gnet_dump d; 818 struct gnet_dump d;
782 819
783 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); 820 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
@@ -811,12 +848,12 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
811 if (gnet_stats_finish_copy(&d) < 0) 848 if (gnet_stats_finish_copy(&d) < 0)
812 goto rtattr_failure; 849 goto rtattr_failure;
813 850
814 nlh->nlmsg_len = skb->tail - b; 851 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
815 return skb->len; 852 return skb->len;
816 853
817nlmsg_failure: 854nlmsg_failure:
818rtattr_failure: 855rtattr_failure:
819 skb_trim(skb, b - skb->data); 856 nlmsg_trim(skb, b);
820 return -1; 857 return -1;
821} 858}
822 859
@@ -862,7 +899,6 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
862 continue; 899 continue;
863 if (idx > s_idx) 900 if (idx > s_idx)
864 s_q_idx = 0; 901 s_q_idx = 0;
865 read_lock(&qdisc_tree_lock);
866 q_idx = 0; 902 q_idx = 0;
867 list_for_each_entry(q, &dev->qdisc_list, list) { 903 list_for_each_entry(q, &dev->qdisc_list, list) {
868 if (q_idx < s_q_idx) { 904 if (q_idx < s_q_idx) {
@@ -870,13 +906,10 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
870 continue; 906 continue;
871 } 907 }
872 if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, 908 if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
873 cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) { 909 cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
874 read_unlock(&qdisc_tree_lock);
875 goto done; 910 goto done;
876 }
877 q_idx++; 911 q_idx++;
878 } 912 }
879 read_unlock(&qdisc_tree_lock);
880 } 913 }
881 914
882done: 915done:
@@ -1015,7 +1048,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
1015{ 1048{
1016 struct tcmsg *tcm; 1049 struct tcmsg *tcm;
1017 struct nlmsghdr *nlh; 1050 struct nlmsghdr *nlh;
1018 unsigned char *b = skb->tail; 1051 unsigned char *b = skb_tail_pointer(skb);
1019 struct gnet_dump d; 1052 struct gnet_dump d;
1020 struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; 1053 struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
1021 1054
@@ -1040,12 +1073,12 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
1040 if (gnet_stats_finish_copy(&d) < 0) 1073 if (gnet_stats_finish_copy(&d) < 0)
1041 goto rtattr_failure; 1074 goto rtattr_failure;
1042 1075
1043 nlh->nlmsg_len = skb->tail - b; 1076 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1044 return skb->len; 1077 return skb->len;
1045 1078
1046nlmsg_failure: 1079nlmsg_failure:
1047rtattr_failure: 1080rtattr_failure:
1048 skb_trim(skb, b - skb->data); 1081 nlmsg_trim(skb, b);
1049 return -1; 1082 return -1;
1050} 1083}
1051 1084
@@ -1099,7 +1132,6 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
1099 s_t = cb->args[0]; 1132 s_t = cb->args[0];
1100 t = 0; 1133 t = 0;
1101 1134
1102 read_lock(&qdisc_tree_lock);
1103 list_for_each_entry(q, &dev->qdisc_list, list) { 1135 list_for_each_entry(q, &dev->qdisc_list, list) {
1104 if (t < s_t || !q->ops->cl_ops || 1136 if (t < s_t || !q->ops->cl_ops ||
1105 (tcm->tcm_parent && 1137 (tcm->tcm_parent &&
@@ -1121,7 +1153,6 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
1121 break; 1153 break;
1122 t++; 1154 t++;
1123 } 1155 }
1124 read_unlock(&qdisc_tree_lock);
1125 1156
1126 cb->args[0] = t; 1157 cb->args[0] = t;
1127 1158
@@ -1146,7 +1177,7 @@ reclassify:
1146 1177
1147 for ( ; tp; tp = tp->next) { 1178 for ( ; tp; tp = tp->next) {
1148 if ((tp->protocol == protocol || 1179 if ((tp->protocol == protocol ||
1149 tp->protocol == __constant_htons(ETH_P_ALL)) && 1180 tp->protocol == htons(ETH_P_ALL)) &&
1150 (err = tp->classify(skb, tp, res)) >= 0) { 1181 (err = tp->classify(skb, tp, res)) >= 0) {
1151#ifdef CONFIG_NET_CLS_ACT 1182#ifdef CONFIG_NET_CLS_ACT
1152 if ( TC_ACT_RECLASSIFY == err) { 1183 if ( TC_ACT_RECLASSIFY == err) {
@@ -1175,15 +1206,31 @@ reclassify:
1175 return -1; 1206 return -1;
1176} 1207}
1177 1208
1178static int psched_us_per_tick = 1; 1209void tcf_destroy(struct tcf_proto *tp)
1179static int psched_tick_per_us = 1; 1210{
1211 tp->ops->destroy(tp);
1212 module_put(tp->ops->owner);
1213 kfree(tp);
1214}
1215
1216void tcf_destroy_chain(struct tcf_proto *fl)
1217{
1218 struct tcf_proto *tp;
1219
1220 while ((tp = fl) != NULL) {
1221 fl = tp->next;
1222 tcf_destroy(tp);
1223 }
1224}
1225EXPORT_SYMBOL(tcf_destroy_chain);
1180 1226
1181#ifdef CONFIG_PROC_FS 1227#ifdef CONFIG_PROC_FS
1182static int psched_show(struct seq_file *seq, void *v) 1228static int psched_show(struct seq_file *seq, void *v)
1183{ 1229{
1184 seq_printf(seq, "%08x %08x %08x %08x\n", 1230 seq_printf(seq, "%08x %08x %08x %08x\n",
1185 psched_tick_per_us, psched_us_per_tick, 1231 (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1),
1186 1000000, HZ); 1232 1000000,
1233 (u32)NSEC_PER_SEC/(u32)ktime_to_ns(KTIME_MONOTONIC_RES));
1187 1234
1188 return 0; 1235 return 0;
1189} 1236}
@@ -1202,101 +1249,19 @@ static const struct file_operations psched_fops = {
1202}; 1249};
1203#endif 1250#endif
1204 1251
1205#ifdef CONFIG_NET_SCH_CLK_CPU
1206psched_tdiff_t psched_clock_per_hz;
1207int psched_clock_scale;
1208EXPORT_SYMBOL(psched_clock_per_hz);
1209EXPORT_SYMBOL(psched_clock_scale);
1210
1211psched_time_t psched_time_base;
1212cycles_t psched_time_mark;
1213EXPORT_SYMBOL(psched_time_mark);
1214EXPORT_SYMBOL(psched_time_base);
1215
1216/*
1217 * Periodically adjust psched_time_base to avoid overflow
1218 * with 32-bit get_cycles(). Safe up to 4GHz CPU.
1219 */
1220static void psched_tick(unsigned long);
1221static DEFINE_TIMER(psched_timer, psched_tick, 0, 0);
1222
1223static void psched_tick(unsigned long dummy)
1224{
1225 if (sizeof(cycles_t) == sizeof(u32)) {
1226 psched_time_t dummy_stamp;
1227 PSCHED_GET_TIME(dummy_stamp);
1228 psched_timer.expires = jiffies + 1*HZ;
1229 add_timer(&psched_timer);
1230 }
1231}
1232
1233int __init psched_calibrate_clock(void)
1234{
1235 psched_time_t stamp, stamp1;
1236 struct timeval tv, tv1;
1237 psched_tdiff_t delay;
1238 long rdelay;
1239 unsigned long stop;
1240
1241 psched_tick(0);
1242 stop = jiffies + HZ/10;
1243 PSCHED_GET_TIME(stamp);
1244 do_gettimeofday(&tv);
1245 while (time_before(jiffies, stop)) {
1246 barrier();
1247 cpu_relax();
1248 }
1249 PSCHED_GET_TIME(stamp1);
1250 do_gettimeofday(&tv1);
1251
1252 delay = PSCHED_TDIFF(stamp1, stamp);
1253 rdelay = tv1.tv_usec - tv.tv_usec;
1254 rdelay += (tv1.tv_sec - tv.tv_sec)*1000000;
1255 if (rdelay > delay)
1256 return -1;
1257 delay /= rdelay;
1258 psched_tick_per_us = delay;
1259 while ((delay>>=1) != 0)
1260 psched_clock_scale++;
1261 psched_us_per_tick = 1<<psched_clock_scale;
1262 psched_clock_per_hz = (psched_tick_per_us*(1000000/HZ))>>psched_clock_scale;
1263 return 0;
1264}
1265#endif
1266
1267static int __init pktsched_init(void) 1252static int __init pktsched_init(void)
1268{ 1253{
1269 struct rtnetlink_link *link_p;
1270
1271#ifdef CONFIG_NET_SCH_CLK_CPU
1272 if (psched_calibrate_clock() < 0)
1273 return -1;
1274#elif defined(CONFIG_NET_SCH_CLK_JIFFIES)
1275 psched_tick_per_us = HZ<<PSCHED_JSCALE;
1276 psched_us_per_tick = 1000000;
1277#endif
1278
1279 link_p = rtnetlink_links[PF_UNSPEC];
1280
1281 /* Setup rtnetlink links. It is made here to avoid
1282 exporting large number of public symbols.
1283 */
1284
1285 if (link_p) {
1286 link_p[RTM_NEWQDISC-RTM_BASE].doit = tc_modify_qdisc;
1287 link_p[RTM_DELQDISC-RTM_BASE].doit = tc_get_qdisc;
1288 link_p[RTM_GETQDISC-RTM_BASE].doit = tc_get_qdisc;
1289 link_p[RTM_GETQDISC-RTM_BASE].dumpit = tc_dump_qdisc;
1290 link_p[RTM_NEWTCLASS-RTM_BASE].doit = tc_ctl_tclass;
1291 link_p[RTM_DELTCLASS-RTM_BASE].doit = tc_ctl_tclass;
1292 link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass;
1293 link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass;
1294 }
1295
1296 register_qdisc(&pfifo_qdisc_ops); 1254 register_qdisc(&pfifo_qdisc_ops);
1297 register_qdisc(&bfifo_qdisc_ops); 1255 register_qdisc(&bfifo_qdisc_ops);
1298 proc_net_fops_create("psched", 0, &psched_fops); 1256 proc_net_fops_create("psched", 0, &psched_fops);
1299 1257
1258 rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);
1259 rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);
1260 rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc);
1261 rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL);
1262 rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL);
1263 rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass);
1264
1300 return 0; 1265 return 0;
1301} 1266}
1302 1267