From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-we0-x22e.google.com (mail-we0-x22e.google.com [IPv6:2a00:1450:400c:c03::22e]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority" (verified OK)) by huchra.bufferbloat.net (Postfix) with ESMTPS id 34AF321F1E1 for ; Wed, 14 Aug 2013 17:46:06 -0700 (PDT) Received: by mail-we0-f174.google.com with SMTP id q54so110487wes.5 for ; Wed, 14 Aug 2013 17:46:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=B6B8woKi6/RUnd8rvRexloYLqaNhrFVVsFOeBbpqwio=; b=dUAIPU9JFOMXOzheKydXOYSbzz1fNeE3LsJ2wY0MjadR2tNUuxc2zCUN8KtkoMG9Br z4FdK80OB65CPPdAiNboswOnoy+S2Mdxlrw77U39PTckLY0mpqIYtcpfloWfJ0E1vxj0 KAdQFgG5ObxBYhImWCiFXgOuL6JN/3kOuvUciI4DLJZkyztInYXYWcqn7HuLEzhpZJlh e1rPYswyh+t7Bua+01BYYhI1BGrzrMzzlGGcd2XZaQilmdp2B0T1qGNp/z1be0UssZMy 5ks/pGW1Aeay5RR9p/3j9CqOejjqS8YiTbpOdnJ6ba2CaELXbD1E7txYwjCxRghtxdIj 0Qkw== MIME-Version: 1.0 X-Received: by 10.180.189.132 with SMTP id gi4mr221302wic.19.1376527563985; Wed, 14 Aug 2013 17:46:03 -0700 (PDT) Received: by 10.217.48.129 with HTTP; Wed, 14 Aug 2013 17:46:03 -0700 (PDT) In-Reply-To: <20130814214711.23885.76734.stgit@dragon> References: <20130814214711.23885.76734.stgit@dragon> Date: Wed, 14 Aug 2013 17:46:03 -0700 Message-ID: From: Dave Taht To: "cerowrt-devel@lists.bufferbloat.net" Content-Type: multipart/alternative; boundary=001a11c35294799b8504e3f1cc1b Subject: [Cerowrt-devel] Fwd: [PATCH] net_sched: restore "linklayer atm" handling X-BeenThere: cerowrt-devel@lists.bufferbloat.net X-Mailman-Version: 2.1.13 Precedence: list List-Id: Development issues regarding the cerowrt test router project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 15 Aug 2013 00:46:06 -0000 --001a11c35294799b8504e3f1cc1b Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable jesper just dropped this set of patches on the netdev list, which I hope address some of the remaining issues on htb. There was some debate the last time this went by on the list, so the word is not in yet. I note I would really like to get around to profiling the "final" aqm code in the hope of squeezing more performance out of it. Presently it tops out at about 25/25Mbit. (it's not fq_codel but htb) ---------- Forwarded message ---------- From: Jesper Dangaard Brouer Date: Wed, Aug 14, 2013 at 2:47 PM Subject: [PATCH] net_sched: restore "linklayer atm" handling To: "David S. Miller" , Dave Taht , netdev@vger.kernel.org Cc: Jesper Dangaard Brouer , Stephen Hemminger < shemminger@vyatta.com> commit 56b765b79 ("htb: improved accuracy at high rates") broke the "linklayer atm" handling. tc class add ... htb rate X ceil Y linklayer atm The linklayer setting is implemented by modifying the rate table which is send to the kernel. No direct parameter were transferred to the kernel indicating the linklayer setting. The commit 56b765b79 ("htb: improved accuracy at high rates") removed the use of the rate table system. To keep compatible with older iproute2 utils, this patch detects the linklayer by parsing the rate table. It also supports future versions of iproute2 to send this linklayer parameter to the kernel directly. This is done by using the __reserved field in struct tc_ratespec, to convey the choosen linklayer option, but only using the lower 4 bits of this field. Linklayer detection is limited to speeds below 100Mbit/s, because at high rates the rtab is gets too inaccurate, so bad that several fields contain the same values, this resembling the ATM detect. Fields even start to contain "0" time to send, e.g. at 1000Mbit/s sending a 96 bytes packet cost "0", thus the rtab have been more broken than we first realized. Signed-off-by: Jesper Dangaard Brouer --- include/net/sch_generic.h | 9 ++++++++- include/uapi/linux/pkt_sched.h | 10 +++++++++- net/sched/sch_api.c | 41 ++++++++++++++++++++++++++++++++++++++++ net/sched/sch_generic.c | 1 + net/sched/sch_htb.c | 13 +++++++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 6eab633..e5ae0c5 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -683,13 +683,19 @@ struct psched_ratecfg { u64 rate_bytes_ps; /* bytes per second */ u32 mult; u16 overhead; + u8 linklayer; u8 shift; }; static inline u64 psched_l2t_ns(const struct psched_ratecfg *r, unsigned int len) { - return ((u64)(len + r->overhead) * r->mult) >> r->shift; + len +=3D r->overhead; + + if (unlikely(r->linklayer =3D=3D TC_LINKLAYER_ATM)) + return ((u64)(DIV_ROUND_UP(len,48)*53) * r->mult) >> r->shift; + + return ((u64)len * r->mult) >> r->shift; } extern void psched_ratecfg_precompute(struct psched_ratecfg *r, const struct tc_ratespec *conf); @@ -700,6 +706,7 @@ static inline void psched_ratecfg_getrate(struct tc_ratespec *res, memset(res, 0, sizeof(*res)); res->rate =3D r->rate_bytes_ps; res->overhead =3D r->overhead; + res->linklayer =3D (r->linklayer & TC_LINKLAYER_MASK); } #endif diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.= h index dbd71b0..09d62b9 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -73,9 +73,17 @@ struct tc_estimator { #define TC_H_ROOT (0xFFFFFFFFU) #define TC_H_INGRESS (0xFFFFFFF1U) +/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */ +enum tc_link_layer { + TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util */ + TC_LINKLAYER_ETHERNET, + TC_LINKLAYER_ATM, +}; +#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */ + struct tc_ratespec { unsigned char cell_log; - unsigned char __reserved; + __u8 linklayer; /* lower 4 bits */ unsigned short overhead; short cell_align; unsigned short mpu; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 281c1bd..51b968d 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) return q; } +/* The linklayer setting were not transferred from iproute2, in older + * versions, and the rate tables lookup systems have been dropped in + * the kernel. To keep backward compatible with older iproute2 tc + * utils, we detect the linklayer setting by detecting if the rate + * table were modified. + * + * For linklayer ATM table entries, the rate table will be aligned to + * 48 bytes, thus some table entries will contain the same value. The + * mpu (min packet unit) is also encoded into the old rate table, thus + * starting from the mpu, we find low and high table entries for + * mapping this cell. If these entries contain the same value, when + * the rate tables have been modified for linklayer ATM. + * + * This is done by rounding mpu to the nearest 48 bytes cell/entry, + * and then roundup to the next cell, calc the table entry one below, + * and compare. + */ +static __u8 __detect_linklayer(struct tc_ratespec *r, __u32 *rtab) +{ + int low =3D roundup(r->mpu, 48); + int high =3D roundup(low+1, 48); + int cell_low =3D low >> r->cell_log; + int cell_high =3D (high >> r->cell_log) - 1; + + /* rtab is too inaccurate at rates > 100Mbit/s */ + if ((r->rate > (100000000/8)) || (rtab[0] =3D=3D 0)) { + pr_debug("TC linklayer: Giving up ATM detection\n"); + return TC_LINKLAYER_ETHERNET; + } + + if ((cell_high > cell_low) && (cell_high < 256) + && (rtab[cell_low] =3D=3D rtab[cell_high])) { + pr_debug("TC linklayer: Detected ATM, low(%d)=3Dhigh(%d)=3D%u\n", + cell_low, cell_high, rtab[cell_high]); + return TC_LINKLAYER_ATM; + } + return TC_LINKLAYER_ETHERNET; +} + static struct qdisc_rate_table *qdisc_rtab_list; 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 rtab->rate =3D *r; rtab->refcnt =3D 1; memcpy(rtab->data, nla_data(tab), 1024); + if (r->linklayer =3D=3D TC_LINKLAYER_UNAWARE) + r->linklayer =3D __detect_linklayer(r, rtab->data); rtab->next =3D qdisc_rtab_list; qdisc_rtab_list =3D rtab; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index eeb8276..48be3d5 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -909,6 +909,7 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r= , memset(r, 0, sizeof(*r)); r->overhead =3D conf->overhead; r->rate_bytes_ps =3D conf->rate; + r->linklayer =3D (conf->linklayer & TC_LINKLAYER_MASK); r->mult =3D 1; /* * 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 45e7515..c2178b1 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, struct htb_sched *q =3D qdisc_priv(sch); struct htb_class *cl =3D (struct htb_class *)*arg, *parent; struct nlattr *opt =3D tca[TCA_OPTIONS]; + struct qdisc_rate_table *rtab =3D NULL, *ctab =3D NULL; struct nlattr *tb[TCA_HTB_MAX + 1]; struct tc_htb_opt *hopt; @@ -1350,6 +1351,18 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, if (!hopt->rate.rate || !hopt->ceil.rate) goto failure; + /* Keeping backward compatible with rate_table based iproute2 tc */ + if (hopt->rate.linklayer =3D=3D TC_LINKLAYER_UNAWARE) { + rtab =3D qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]); + if (rtab) + qdisc_put_rtab(rtab); + } + if (hopt->ceil.linklayer =3D=3D TC_LINKLAYER_UNAWARE) { + ctab =3D qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]); + if (ctab) + qdisc_put_rtab(ctab); + } + if (!cl) { /* new class */ struct Qdisc *new_q; int prio; --=20 Dave T=E4ht Fixing bufferbloat with cerowrt: http://www.teklibre.com/cerowrt/subscribe.html --001a11c35294799b8504e3f1cc1b Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
jesper just dropped this set of patches on the netdev list= , which I hope address some of the remaining issues on htb. There was some = debate the last time this went by on the list, so the word is not in yet.
I note I would really like to get around to profiling the "final&q= uot; aqm code in the hope of squeezing more performance out of it. Presentl= y it tops out at about 25/25Mbit. (it's not fq_codel but htb)

---------- Forwarded message ----------
F= rom: Jesper Dangaard Brouer <brouer@redhat.com>
Date: Wed, Aug 14, 2013 at 2:47 PM
Subject: [PATCH] net_sched: restore &= quot;linklayer atm" handling
To: "David S. Miller" <davem@davemloft.net>, Dave Taht= <dave.taht@gmail.com>, netdev@vger.kernel.org
Cc: Jesper Dangaard Brouer <brouer@= redhat.com>, Stephen Hemminger <shemminger@vyatta.com>


commit 56b765b79 ("ht= b: improved accuracy at high rates")
broke the "linklayer atm" handling.

=A0tc class add ... htb rate X ceil Y linklayer atm

The linklayer setting is implemented by modifying the rate table
which is send to the kernel. =A0No direct parameter were
transferred to the kernel indicating the linklayer setting.

The commit 56b765b79 ("htb: improved accuracy at high rates")
removed the use of the rate table system.

To keep compatible with older iproute2 utils, this patch detects
the linklayer by parsing the rate table. =A0It also supports future
versions of iproute2 to send this linklayer parameter to the
kernel directly. This is done by using the __reserved field in
struct tc_ratespec, to convey the choosen linklayer option, but
only using the lower 4 bits of this field.

Linklayer detection is limited to speeds below 100Mbit/s, because
at high rates the rtab is gets too inaccurate, so bad that
several fields contain the same values, this resembling the ATM
detect. =A0Fields even start to contain "0" time to send, e.g. at=
1000Mbit/s sending a 96 bytes packet cost "0", thus the rtab have=
been more broken than we first realized.

Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
---

=A0include/net/sch_generic.h =A0 =A0 =A0| =A0 =A09 ++++++++-
=A0include/uapi/linux/pkt_sched.h | =A0 10 +++++++++-
=A0net/sched/sch_api.c =A0 =A0 =A0 =A0 =A0 =A0| =A0 41 ++++++++++++++++++++= ++++++++++++++++++++
=A0net/sched/sch_generic.c =A0 =A0 =A0 =A0| =A0 =A01 +
=A0net/sched/sch_htb.c =A0 =A0 =A0 =A0 =A0 =A0| =A0 13 +++++++++++++
=A05 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 6eab633..e5ae0c5 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -683,13 +683,19 @@ struct psched_ratecfg {
=A0 =A0 =A0 =A0 u64 =A0 =A0 rate_bytes_ps; /* bytes per second */
=A0 =A0 =A0 =A0 u32 =A0 =A0 mult;
=A0 =A0 =A0 =A0 u16 =A0 =A0 overhead;
+ =A0 =A0 =A0 u8 =A0 =A0 =A0linklayer;
=A0 =A0 =A0 =A0 u8 =A0 =A0 =A0shift;
=A0};

=A0static inline u64 psched_l2t_ns(const struct psched_ratecfg *r,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned in= t len)
=A0{
- =A0 =A0 =A0 return ((u64)(len + r->overhead) * r->mult) >> r-= >shift;
+ =A0 =A0 =A0 len +=3D r->overhead;
+
+ =A0 =A0 =A0 if (unlikely(r->linklayer =3D=3D TC_LINKLAYER_ATM))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return ((u64)(DIV_ROUND_UP(len,48)*53) * r-&g= t;mult) >> r->shift;
+
+ =A0 =A0 =A0 return ((u64)len * r->mult) >> r->shift;
=A0}

=A0extern void psched_ratecfg_precompute(struct psched_ratecfg *r, const st= ruct tc_ratespec *conf);
@@ -700,6 +706,7 @@ static inline void psched_ratecfg_getrate(struct tc_rat= espec *res,
=A0 =A0 =A0 =A0 memset(res, 0, sizeof(*res));
=A0 =A0 =A0 =A0 res->rate =3D r->rate_bytes_ps;
=A0 =A0 =A0 =A0 res->overhead =3D r->overhead;
+ =A0 =A0 =A0 res->linklayer =3D (r->linklayer & TC_LINKLAYER_MAS= K);
=A0}

=A0#endif
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.= h
index dbd71b0..09d62b9 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -73,9 +73,17 @@ struct tc_estimator {
=A0#define TC_H_ROOT =A0 =A0 =A0(0xFFFFFFFFU)
=A0#define TC_H_INGRESS =A0 =A0(0xFFFFFFF1U)

+/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer"= */
+enum tc_link_layer {
+ =A0 =A0 =A0 TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util *= /
+ =A0 =A0 =A0 TC_LINKLAYER_ETHERNET,
+ =A0 =A0 =A0 TC_LINKLAYER_ATM,
+};
+#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */
+
=A0struct tc_ratespec {
=A0 =A0 =A0 =A0 unsigned char =A0 cell_log;
- =A0 =A0 =A0 unsigned char =A0 __reserved;
+ =A0 =A0 =A0 __u8 =A0 =A0 =A0 =A0 =A0 =A0linklayer; /* lower 4 bits */
=A0 =A0 =A0 =A0 unsigned short =A0overhead;
=A0 =A0 =A0 =A0 short =A0 =A0 =A0 =A0 =A0 cell_align;
=A0 =A0 =A0 =A0 unsigned short =A0mpu;
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 281c1bd..51b968d 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 nlatt= r *kind)
=A0 =A0 =A0 =A0 return q;
=A0}

+/* The linklayer setting were not transferred from iproute2, in older
+ * versions, and the rate tables lookup systems have been dropped in
+ * the kernel. To keep backward compatible with older iproute2 tc
+ * utils, we detect the linklayer setting by detecting if the rate
+ * table were modified.
+ *
+ * For linklayer ATM table entries, the rate table will be aligned to
+ * 48 bytes, thus some table entries will contain the same value. =A0The + * mpu (min packet unit) is also encoded into the old rate table, thus
+ * starting from the mpu, we find low and high table entries for
+ * mapping this cell. =A0If these entries contain the same value, when
+ * the rate tables have been modified for linklayer ATM.
+ *
+ * This is done by rounding mpu to the nearest 48 bytes cell/entry,
+ * and then roundup to the next cell, calc the table entry one below,
+ * and compare.
+ */
+static __u8 __detect_linklayer(struct tc_ratespec *r, __u32 *rtab)
+{
+ =A0 =A0 =A0 int low =A0 =A0 =A0 =3D roundup(r->mpu, 48);
+ =A0 =A0 =A0 int high =A0 =A0 =A0=3D roundup(low+1, 48);
+ =A0 =A0 =A0 int cell_low =A0=3D low >> r->cell_log;
+ =A0 =A0 =A0 int cell_high =3D (high >> r->cell_log) - 1;
+
+ =A0 =A0 =A0 /* rtab is too inaccurate at rates > 100Mbit/s */
+ =A0 =A0 =A0 if ((r->rate > (100000000/8)) || (rtab[0] =3D=3D 0)) {<= br> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("TC linklayer: Giving up ATM de= tection\n");
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return TC_LINKLAYER_ETHERNET;
+ =A0 =A0 =A0 }
+
+ =A0 =A0 =A0 if ((cell_high > cell_low) && (cell_high < 256)=
+ =A0 =A0 =A0 =A0 =A0 && (rtab[cell_low] =3D=3D rtab[cell_high])) {=
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("TC linklayer: Detected ATM, lo= w(%d)=3Dhigh(%d)=3D%u\n",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cell_low, cell_high, rtab[= cell_high]);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return TC_LINKLAYER_ATM;
+ =A0 =A0 =A0 }
+ =A0 =A0 =A0 return TC_LINKLAYER_ETHERNET;
+}
+
=A0static struct qdisc_rate_table *qdisc_rtab_list;

=A0struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nl= attr *tab)
@@ -308,6 +347,8 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_rates= pec *r, struct nlattr *ta
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtab->rate =3D *r;
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtab->refcnt =3D 1;
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy(rtab->data, nla_data(tab), 1024);=
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (r->linklayer =3D=3D TC_LINKLAYER_UNAWA= RE)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 r->linklayer =3D __detect_= linklayer(r, rtab->data);
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtab->next =3D qdisc_rtab_list;
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_rtab_list =3D rtab;
=A0 =A0 =A0 =A0 }
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index eeb8276..48be3d5 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -909,6 +909,7 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r= ,
=A0 =A0 =A0 =A0 memset(r, 0, sizeof(*r));
=A0 =A0 =A0 =A0 r->overhead =3D conf->overhead;
=A0 =A0 =A0 =A0 r->rate_bytes_ps =3D conf->rate;
+ =A0 =A0 =A0 r->linklayer =3D (conf->linklayer & TC_LINKLAYER_MA= SK);
=A0 =A0 =A0 =A0 r->mult =3D 1;
=A0 =A0 =A0 =A0 /*
=A0 =A0 =A0 =A0 =A0* The deal here is to replace a divide by a reciprocal o= ne
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 45e7515..c2178b1 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 cl= assid,
=A0 =A0 =A0 =A0 struct htb_sched *q =3D qdisc_priv(sch);
=A0 =A0 =A0 =A0 struct htb_class *cl =3D (struct htb_class *)*arg, *parent;=
=A0 =A0 =A0 =A0 struct nlattr *opt =3D tca[TCA_OPTIONS];
+ =A0 =A0 =A0 struct qdisc_rate_table *rtab =3D NULL, *ctab =3D NULL;
=A0 =A0 =A0 =A0 struct nlattr *tb[TCA_HTB_MAX + 1];
=A0 =A0 =A0 =A0 struct tc_htb_opt *hopt;

@@ -1350,6 +1351,18 @@ static int htb_change_class(struct Qdisc *sch, u32 c= lassid,
=A0 =A0 =A0 =A0 if (!hopt->rate.rate || !hopt->ceil.rate)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto failure;

+ =A0 =A0 =A0 /* Keeping backward compatible with rate_table based iproute2= tc */
+ =A0 =A0 =A0 if (hopt->rate.linklayer =3D=3D TC_LINKLAYER_UNAWARE) { + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtab =3D qdisc_get_rtab(&hopt->rate, t= b[TCA_HTB_RTAB]);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rtab)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_put_rtab(rtab);
+ =A0 =A0 =A0 }
+ =A0 =A0 =A0 if (hopt->ceil.linklayer =3D=3D TC_LINKLAYER_UNAWARE) { + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ctab =3D qdisc_get_rtab(&hopt->ceil, t= b[TCA_HTB_CTAB]);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ctab)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_put_rtab(ctab);
+ =A0 =A0 =A0 }
+
=A0 =A0 =A0 =A0 if (!cl) { =A0 =A0 =A0 =A0 =A0 =A0 =A0/* new class */
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct Qdisc *new_q;
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int prio;




--
Dave T=E4ht

Fixing bufferbloa= t with cerowrt: http://www.teklibre.com/cerowrt/subscribe.html=20
--001a11c35294799b8504e3f1cc1b--