diff options
-rw-r--r-- | Documentation/sysctl/net.txt | 13 | ||||
-rw-r--r-- | include/net/pkt_sched.h | 3 | ||||
-rw-r--r-- | include/net/sch_generic.h | 1 | ||||
-rw-r--r-- | net/core/sysctl_net_core.c | 30 | ||||
-rw-r--r-- | net/sched/sch_api.c | 58 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 11 | ||||
-rw-r--r-- | net/sched/sch_mq.c | 2 | ||||
-rw-r--r-- | net/sched/sch_mqprio.c | 2 |
8 files changed, 112 insertions, 8 deletions
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index d569f2a424d5..9a0319a82470 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt | |||
@@ -50,6 +50,19 @@ The maximum number of packets that kernel can handle on a NAPI interrupt, | |||
50 | it's a Per-CPU variable. | 50 | it's a Per-CPU variable. |
51 | Default: 64 | 51 | Default: 64 |
52 | 52 | ||
53 | default_qdisc | ||
54 | -------------- | ||
55 | |||
56 | The default queuing discipline to use for network devices. This allows | ||
57 | overriding the default queue discipline of pfifo_fast with an | ||
58 | alternative. Since the default queuing discipline is created with the | ||
59 | no additional parameters so is best suited to queuing disciplines that | ||
60 | work well without configuration like stochastic fair queue (sfq), | ||
61 | CoDel (codel) or fair queue CoDel (fq_codel). Don't use queuing disciplines | ||
62 | like Hierarchical Token Bucket or Deficit Round Robin which require setting | ||
63 | up classes and bandwidths. | ||
64 | Default: pfifo_fast | ||
65 | |||
53 | busy_read | 66 | busy_read |
54 | ---------------- | 67 | ---------------- |
55 | Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL) | 68 | Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL) |
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index f7c24f8fbdc5..59ec3cd15d68 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h | |||
@@ -85,6 +85,9 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, | |||
85 | 85 | ||
86 | int register_qdisc(struct Qdisc_ops *qops); | 86 | int register_qdisc(struct Qdisc_ops *qops); |
87 | int unregister_qdisc(struct Qdisc_ops *qops); | 87 | int unregister_qdisc(struct Qdisc_ops *qops); |
88 | void qdisc_get_default(char *id, size_t len); | ||
89 | int qdisc_set_default(const char *id); | ||
90 | |||
88 | void qdisc_list_del(struct Qdisc *q); | 91 | void qdisc_list_del(struct Qdisc *q); |
89 | struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); | 92 | struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); |
90 | struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); | 93 | struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); |
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 76368c9d4503..2e31bf14df00 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h | |||
@@ -316,6 +316,7 @@ extern struct Qdisc noop_qdisc; | |||
316 | extern struct Qdisc_ops noop_qdisc_ops; | 316 | extern struct Qdisc_ops noop_qdisc_ops; |
317 | extern struct Qdisc_ops pfifo_fast_ops; | 317 | extern struct Qdisc_ops pfifo_fast_ops; |
318 | extern struct Qdisc_ops mq_qdisc_ops; | 318 | extern struct Qdisc_ops mq_qdisc_ops; |
319 | extern const struct Qdisc_ops *default_qdisc_ops; | ||
319 | 320 | ||
320 | struct Qdisc_class_common { | 321 | struct Qdisc_class_common { |
321 | u32 classid; | 322 | u32 classid; |
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 31107abd2783..cca444190907 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <net/sock.h> | 20 | #include <net/sock.h> |
21 | #include <net/net_ratelimit.h> | 21 | #include <net/net_ratelimit.h> |
22 | #include <net/busy_poll.h> | 22 | #include <net/busy_poll.h> |
23 | #include <net/pkt_sched.h> | ||
23 | 24 | ||
24 | static int zero = 0; | 25 | static int zero = 0; |
25 | static int one = 1; | 26 | static int one = 1; |
@@ -193,6 +194,26 @@ static int flow_limit_table_len_sysctl(struct ctl_table *table, int write, | |||
193 | } | 194 | } |
194 | #endif /* CONFIG_NET_FLOW_LIMIT */ | 195 | #endif /* CONFIG_NET_FLOW_LIMIT */ |
195 | 196 | ||
197 | #ifdef CONFIG_NET_SCHED | ||
198 | static int set_default_qdisc(struct ctl_table *table, int write, | ||
199 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
200 | { | ||
201 | char id[IFNAMSIZ]; | ||
202 | struct ctl_table tbl = { | ||
203 | .data = id, | ||
204 | .maxlen = IFNAMSIZ, | ||
205 | }; | ||
206 | int ret; | ||
207 | |||
208 | qdisc_get_default(id, IFNAMSIZ); | ||
209 | |||
210 | ret = proc_dostring(&tbl, write, buffer, lenp, ppos); | ||
211 | if (write && ret == 0) | ||
212 | ret = qdisc_set_default(id); | ||
213 | return ret; | ||
214 | } | ||
215 | #endif | ||
216 | |||
196 | static struct ctl_table net_core_table[] = { | 217 | static struct ctl_table net_core_table[] = { |
197 | #ifdef CONFIG_NET | 218 | #ifdef CONFIG_NET |
198 | { | 219 | { |
@@ -315,7 +336,14 @@ static struct ctl_table net_core_table[] = { | |||
315 | .mode = 0644, | 336 | .mode = 0644, |
316 | .proc_handler = proc_dointvec | 337 | .proc_handler = proc_dointvec |
317 | }, | 338 | }, |
318 | # | 339 | #endif |
340 | #ifdef CONFIG_NET_SCHED | ||
341 | { | ||
342 | .procname = "default_qdisc", | ||
343 | .mode = 0644, | ||
344 | .maxlen = IFNAMSIZ, | ||
345 | .proc_handler = set_default_qdisc | ||
346 | }, | ||
319 | #endif | 347 | #endif |
320 | #endif /* CONFIG_NET */ | 348 | #endif /* CONFIG_NET */ |
321 | { | 349 | { |
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 51b968d3febb..812e57900591 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -131,6 +131,11 @@ static DEFINE_RWLOCK(qdisc_mod_lock); | |||
131 | ************************************************/ | 131 | ************************************************/ |
132 | 132 | ||
133 | 133 | ||
134 | /* Qdisc to use by default */ | ||
135 | |||
136 | const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; | ||
137 | EXPORT_SYMBOL(default_qdisc_ops); | ||
138 | |||
134 | /* The list of all installed queueing disciplines. */ | 139 | /* The list of all installed queueing disciplines. */ |
135 | 140 | ||
136 | static struct Qdisc_ops *qdisc_base; | 141 | static struct Qdisc_ops *qdisc_base; |
@@ -200,6 +205,58 @@ int unregister_qdisc(struct Qdisc_ops *qops) | |||
200 | } | 205 | } |
201 | EXPORT_SYMBOL(unregister_qdisc); | 206 | EXPORT_SYMBOL(unregister_qdisc); |
202 | 207 | ||
208 | /* Get default qdisc if not otherwise specified */ | ||
209 | void qdisc_get_default(char *name, size_t len) | ||
210 | { | ||
211 | read_lock(&qdisc_mod_lock); | ||
212 | strlcpy(name, default_qdisc_ops->id, len); | ||
213 | read_unlock(&qdisc_mod_lock); | ||
214 | } | ||
215 | |||
216 | static struct Qdisc_ops *qdisc_lookup_default(const char *name) | ||
217 | { | ||
218 | struct Qdisc_ops *q = NULL; | ||
219 | |||
220 | for (q = qdisc_base; q; q = q->next) { | ||
221 | if (!strcmp(name, q->id)) { | ||
222 | if (!try_module_get(q->owner)) | ||
223 | q = NULL; | ||
224 | break; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | return q; | ||
229 | } | ||
230 | |||
231 | /* Set new default qdisc to use */ | ||
232 | int qdisc_set_default(const char *name) | ||
233 | { | ||
234 | const struct Qdisc_ops *ops; | ||
235 | |||
236 | if (!capable(CAP_NET_ADMIN)) | ||
237 | return -EPERM; | ||
238 | |||
239 | write_lock(&qdisc_mod_lock); | ||
240 | ops = qdisc_lookup_default(name); | ||
241 | if (!ops) { | ||
242 | /* Not found, drop lock and try to load module */ | ||
243 | write_unlock(&qdisc_mod_lock); | ||
244 | request_module("sch_%s", name); | ||
245 | write_lock(&qdisc_mod_lock); | ||
246 | |||
247 | ops = qdisc_lookup_default(name); | ||
248 | } | ||
249 | |||
250 | if (ops) { | ||
251 | /* Set new default */ | ||
252 | module_put(default_qdisc_ops->owner); | ||
253 | default_qdisc_ops = ops; | ||
254 | } | ||
255 | write_unlock(&qdisc_mod_lock); | ||
256 | |||
257 | return ops ? 0 : -ENOENT; | ||
258 | } | ||
259 | |||
203 | /* We know handle. Find qdisc among all qdisc's attached to device | 260 | /* We know handle. Find qdisc among all qdisc's attached to device |
204 | (root qdisc, all its children, children of children etc.) | 261 | (root qdisc, all its children, children of children etc.) |
205 | */ | 262 | */ |
@@ -1854,6 +1911,7 @@ static int __init pktsched_init(void) | |||
1854 | return err; | 1911 | return err; |
1855 | } | 1912 | } |
1856 | 1913 | ||
1914 | register_qdisc(&pfifo_fast_ops); | ||
1857 | register_qdisc(&pfifo_qdisc_ops); | 1915 | register_qdisc(&pfifo_qdisc_ops); |
1858 | register_qdisc(&bfifo_qdisc_ops); | 1916 | register_qdisc(&bfifo_qdisc_ops); |
1859 | register_qdisc(&pfifo_head_drop_qdisc_ops); | 1917 | register_qdisc(&pfifo_head_drop_qdisc_ops); |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 48be3d5c0d92..5078e0c5db8d 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -530,7 +530,6 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = { | |||
530 | .dump = pfifo_fast_dump, | 530 | .dump = pfifo_fast_dump, |
531 | .owner = THIS_MODULE, | 531 | .owner = THIS_MODULE, |
532 | }; | 532 | }; |
533 | EXPORT_SYMBOL(pfifo_fast_ops); | ||
534 | 533 | ||
535 | static struct lock_class_key qdisc_tx_busylock; | 534 | static struct lock_class_key qdisc_tx_busylock; |
536 | 535 | ||
@@ -583,6 +582,9 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, | |||
583 | { | 582 | { |
584 | struct Qdisc *sch; | 583 | struct Qdisc *sch; |
585 | 584 | ||
585 | if (!try_module_get(ops->owner)) | ||
586 | goto errout; | ||
587 | |||
586 | sch = qdisc_alloc(dev_queue, ops); | 588 | sch = qdisc_alloc(dev_queue, ops); |
587 | if (IS_ERR(sch)) | 589 | if (IS_ERR(sch)) |
588 | goto errout; | 590 | goto errout; |
@@ -686,7 +688,7 @@ static void attach_one_default_qdisc(struct net_device *dev, | |||
686 | 688 | ||
687 | if (dev->tx_queue_len) { | 689 | if (dev->tx_queue_len) { |
688 | qdisc = qdisc_create_dflt(dev_queue, | 690 | qdisc = qdisc_create_dflt(dev_queue, |
689 | &pfifo_fast_ops, TC_H_ROOT); | 691 | default_qdisc_ops, TC_H_ROOT); |
690 | if (!qdisc) { | 692 | if (!qdisc) { |
691 | netdev_info(dev, "activation failed\n"); | 693 | netdev_info(dev, "activation failed\n"); |
692 | return; | 694 | return; |
@@ -739,9 +741,8 @@ void dev_activate(struct net_device *dev) | |||
739 | int need_watchdog; | 741 | int need_watchdog; |
740 | 742 | ||
741 | /* No queueing discipline is attached to device; | 743 | /* No queueing discipline is attached to device; |
742 | create default one i.e. pfifo_fast for devices, | 744 | * create default one for devices, which need queueing |
743 | which need queueing and noqueue_qdisc for | 745 | * and noqueue_qdisc for virtual interfaces |
744 | virtual interfaces | ||
745 | */ | 746 | */ |
746 | 747 | ||
747 | if (dev->qdisc == &noop_qdisc) | 748 | if (dev->qdisc == &noop_qdisc) |
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index 5da78a19ac9a..2e56185736d6 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c | |||
@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt) | |||
57 | 57 | ||
58 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { | 58 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { |
59 | dev_queue = netdev_get_tx_queue(dev, ntx); | 59 | dev_queue = netdev_get_tx_queue(dev, ntx); |
60 | qdisc = qdisc_create_dflt(dev_queue, &pfifo_fast_ops, | 60 | qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, |
61 | TC_H_MAKE(TC_H_MAJ(sch->handle), | 61 | TC_H_MAKE(TC_H_MAJ(sch->handle), |
62 | TC_H_MIN(ntx + 1))); | 62 | TC_H_MIN(ntx + 1))); |
63 | if (qdisc == NULL) | 63 | if (qdisc == NULL) |
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index accec33c454c..d44c868cb537 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c | |||
@@ -124,7 +124,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) | |||
124 | 124 | ||
125 | for (i = 0; i < dev->num_tx_queues; i++) { | 125 | for (i = 0; i < dev->num_tx_queues; i++) { |
126 | dev_queue = netdev_get_tx_queue(dev, i); | 126 | dev_queue = netdev_get_tx_queue(dev, i); |
127 | qdisc = qdisc_create_dflt(dev_queue, &pfifo_fast_ops, | 127 | qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, |
128 | TC_H_MAKE(TC_H_MAJ(sch->handle), | 128 | TC_H_MAKE(TC_H_MAJ(sch->handle), |
129 | TC_H_MIN(i + 1))); | 129 | TC_H_MIN(i + 1))); |
130 | if (qdisc == NULL) { | 130 | if (qdisc == NULL) { |