diff options
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r-- | net/sched/sch_api.c | 41 |
1 files changed, 41 insertions, 0 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 | } |