diff options
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_api.c | 41 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 8 | ||||
-rw-r--r-- | net/sched/sch_htb.c | 13 |
3 files changed, 61 insertions, 1 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 281c1bded1f6..51b968d3febb 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -285,6 +285,45 @@ static struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind) | |||
285 | return q; | 285 | return q; |
286 | } | 286 | } |
287 | 287 | ||
288 | /* The linklayer setting were not transferred from iproute2, in older | ||
289 | * versions, and the rate tables lookup systems have been dropped in | ||
290 | * the kernel. To keep backward compatible with older iproute2 tc | ||
291 | * utils, we detect the linklayer setting by detecting if the rate | ||
292 | * table were modified. | ||
293 | * | ||
294 | * For linklayer ATM table entries, the rate table will be aligned to | ||
295 | * 48 bytes, thus some table entries will contain the same value. The | ||
296 | * mpu (min packet unit) is also encoded into the old rate table, thus | ||
297 | * starting from the mpu, we find low and high table entries for | ||
298 | * mapping this cell. If these entries contain the same value, when | ||
299 | * the rate tables have been modified for linklayer ATM. | ||
300 | * | ||
301 | * This is done by rounding mpu to the nearest 48 bytes cell/entry, | ||
302 | * and then roundup to the next cell, calc the table entry one below, | ||
303 | * and compare. | ||
304 | */ | ||
305 | static __u8 __detect_linklayer(struct tc_ratespec *r, __u32 *rtab) | ||
306 | { | ||
307 | int low = roundup(r->mpu, 48); | ||
308 | int high = roundup(low+1, 48); | ||
309 | int cell_low = low >> r->cell_log; | ||
310 | int cell_high = (high >> r->cell_log) - 1; | ||
311 | |||
312 | /* rtab is too inaccurate at rates > 100Mbit/s */ | ||
313 | if ((r->rate > (100000000/8)) || (rtab[0] == 0)) { | ||
314 | pr_debug("TC linklayer: Giving up ATM detection\n"); | ||
315 | return TC_LINKLAYER_ETHERNET; | ||
316 | } | ||
317 | |||
318 | if ((cell_high > cell_low) && (cell_high < 256) | ||
319 | && (rtab[cell_low] == rtab[cell_high])) { | ||
320 | pr_debug("TC linklayer: Detected ATM, low(%d)=high(%d)=%u\n", | ||
321 | cell_low, cell_high, rtab[cell_high]); | ||
322 | return TC_LINKLAYER_ATM; | ||
323 | } | ||
324 | return TC_LINKLAYER_ETHERNET; | ||
325 | } | ||
326 | |||
288 | static struct qdisc_rate_table *qdisc_rtab_list; | 327 | static struct qdisc_rate_table *qdisc_rtab_list; |
289 | 328 | ||
290 | struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab) | 329 | struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab) |
@@ -308,6 +347,8 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *ta | |||
308 | rtab->rate = *r; | 347 | rtab->rate = *r; |
309 | rtab->refcnt = 1; | 348 | rtab->refcnt = 1; |
310 | memcpy(rtab->data, nla_data(tab), 1024); | 349 | memcpy(rtab->data, nla_data(tab), 1024); |
350 | if (r->linklayer == TC_LINKLAYER_UNAWARE) | ||
351 | r->linklayer = __detect_linklayer(r, rtab->data); | ||
311 | rtab->next = qdisc_rtab_list; | 352 | rtab->next = qdisc_rtab_list; |
312 | qdisc_rtab_list = rtab; | 353 | qdisc_rtab_list = rtab; |
313 | } | 354 | } |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 4626cef4b76e..48be3d5c0d92 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/rcupdate.h> | 25 | #include <linux/rcupdate.h> |
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/if_vlan.h> | ||
28 | #include <net/sch_generic.h> | 29 | #include <net/sch_generic.h> |
29 | #include <net/pkt_sched.h> | 30 | #include <net/pkt_sched.h> |
30 | #include <net/dst.h> | 31 | #include <net/dst.h> |
@@ -207,15 +208,19 @@ void __qdisc_run(struct Qdisc *q) | |||
207 | 208 | ||
208 | unsigned long dev_trans_start(struct net_device *dev) | 209 | unsigned long dev_trans_start(struct net_device *dev) |
209 | { | 210 | { |
210 | unsigned long val, res = dev->trans_start; | 211 | unsigned long val, res; |
211 | unsigned int i; | 212 | unsigned int i; |
212 | 213 | ||
214 | if (is_vlan_dev(dev)) | ||
215 | dev = vlan_dev_real_dev(dev); | ||
216 | res = dev->trans_start; | ||
213 | for (i = 0; i < dev->num_tx_queues; i++) { | 217 | for (i = 0; i < dev->num_tx_queues; i++) { |
214 | val = netdev_get_tx_queue(dev, i)->trans_start; | 218 | val = netdev_get_tx_queue(dev, i)->trans_start; |
215 | if (val && time_after(val, res)) | 219 | if (val && time_after(val, res)) |
216 | res = val; | 220 | res = val; |
217 | } | 221 | } |
218 | dev->trans_start = res; | 222 | dev->trans_start = res; |
223 | |||
219 | return res; | 224 | return res; |
220 | } | 225 | } |
221 | EXPORT_SYMBOL(dev_trans_start); | 226 | EXPORT_SYMBOL(dev_trans_start); |
@@ -904,6 +909,7 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r, | |||
904 | memset(r, 0, sizeof(*r)); | 909 | memset(r, 0, sizeof(*r)); |
905 | r->overhead = conf->overhead; | 910 | r->overhead = conf->overhead; |
906 | r->rate_bytes_ps = conf->rate; | 911 | r->rate_bytes_ps = conf->rate; |
912 | r->linklayer = (conf->linklayer & TC_LINKLAYER_MASK); | ||
907 | r->mult = 1; | 913 | r->mult = 1; |
908 | /* | 914 | /* |
909 | * The deal here is to replace a divide by a reciprocal one | 915 | * The deal here is to replace a divide by a reciprocal one |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 45e751527dfc..c2178b15ca6e 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -1329,6 +1329,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1329 | struct htb_sched *q = qdisc_priv(sch); | 1329 | struct htb_sched *q = qdisc_priv(sch); |
1330 | struct htb_class *cl = (struct htb_class *)*arg, *parent; | 1330 | struct htb_class *cl = (struct htb_class *)*arg, *parent; |
1331 | struct nlattr *opt = tca[TCA_OPTIONS]; | 1331 | struct nlattr *opt = tca[TCA_OPTIONS]; |
1332 | struct qdisc_rate_table *rtab = NULL, *ctab = NULL; | ||
1332 | struct nlattr *tb[TCA_HTB_MAX + 1]; | 1333 | struct nlattr *tb[TCA_HTB_MAX + 1]; |
1333 | struct tc_htb_opt *hopt; | 1334 | struct tc_htb_opt *hopt; |
1334 | 1335 | ||
@@ -1350,6 +1351,18 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1350 | if (!hopt->rate.rate || !hopt->ceil.rate) | 1351 | if (!hopt->rate.rate || !hopt->ceil.rate) |
1351 | goto failure; | 1352 | goto failure; |
1352 | 1353 | ||
1354 | /* Keeping backward compatible with rate_table based iproute2 tc */ | ||
1355 | if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) { | ||
1356 | rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]); | ||
1357 | if (rtab) | ||
1358 | qdisc_put_rtab(rtab); | ||
1359 | } | ||
1360 | if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) { | ||
1361 | ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]); | ||
1362 | if (ctab) | ||
1363 | qdisc_put_rtab(ctab); | ||
1364 | } | ||
1365 | |||
1353 | if (!cl) { /* new class */ | 1366 | if (!cl) { /* new class */ |
1354 | struct Qdisc *new_q; | 1367 | struct Qdisc *new_q; |
1355 | int prio; | 1368 | int prio; |