@@ -114,6 +114,7 @@ struct htb_class {
114114 * Written often fields
115115 */
116116 struct gnet_stats_basic_packed bstats ;
117+ struct gnet_stats_basic_packed bstats_bias ;
117118 struct tc_htb_xstats xstats ; /* our special stats */
118119
119120 /* token bucket parameters */
@@ -1220,6 +1221,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
12201221 struct sk_buff * skb , struct tcmsg * tcm )
12211222{
12221223 struct htb_class * cl = (struct htb_class * )arg ;
1224+ struct htb_sched * q = qdisc_priv (sch );
12231225 struct nlattr * nest ;
12241226 struct tc_htb_opt opt ;
12251227
@@ -1246,6 +1248,8 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
12461248 opt .level = cl -> level ;
12471249 if (nla_put (skb , TCA_HTB_PARMS , sizeof (opt ), & opt ))
12481250 goto nla_put_failure ;
1251+ if (q -> offload && nla_put_flag (skb , TCA_HTB_OFFLOAD ))
1252+ goto nla_put_failure ;
12491253 if ((cl -> rate .rate_bytes_ps >= (1ULL << 32 )) &&
12501254 nla_put_u64_64bit (skb , TCA_HTB_RATE64 , cl -> rate .rate_bytes_ps ,
12511255 TCA_HTB_PAD ))
@@ -1262,10 +1266,39 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
12621266 return -1 ;
12631267}
12641268
1269+ static void htb_offload_aggregate_stats (struct htb_sched * q ,
1270+ struct htb_class * cl )
1271+ {
1272+ struct htb_class * c ;
1273+ unsigned int i ;
1274+
1275+ memset (& cl -> bstats , 0 , sizeof (cl -> bstats ));
1276+
1277+ for (i = 0 ; i < q -> clhash .hashsize ; i ++ ) {
1278+ hlist_for_each_entry (c , & q -> clhash .hash [i ], common .hnode ) {
1279+ struct htb_class * p = c ;
1280+
1281+ while (p && p -> level < cl -> level )
1282+ p = p -> parent ;
1283+
1284+ if (p != cl )
1285+ continue ;
1286+
1287+ cl -> bstats .bytes += c -> bstats_bias .bytes ;
1288+ cl -> bstats .packets += c -> bstats_bias .packets ;
1289+ if (c -> level == 0 ) {
1290+ cl -> bstats .bytes += c -> leaf .q -> bstats .bytes ;
1291+ cl -> bstats .packets += c -> leaf .q -> bstats .packets ;
1292+ }
1293+ }
1294+ }
1295+ }
1296+
12651297static int
12661298htb_dump_class_stats (struct Qdisc * sch , unsigned long arg , struct gnet_dump * d )
12671299{
12681300 struct htb_class * cl = (struct htb_class * )arg ;
1301+ struct htb_sched * q = qdisc_priv (sch );
12691302 struct gnet_stats_queue qs = {
12701303 .drops = cl -> drops ,
12711304 .overlimits = cl -> overlimits ,
@@ -1280,6 +1313,19 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
12801313 cl -> xstats .ctokens = clamp_t (s64 , PSCHED_NS2TICKS (cl -> ctokens ),
12811314 INT_MIN , INT_MAX );
12821315
1316+ if (q -> offload ) {
1317+ if (!cl -> level ) {
1318+ if (cl -> leaf .q )
1319+ cl -> bstats = cl -> leaf .q -> bstats ;
1320+ else
1321+ memset (& cl -> bstats , 0 , sizeof (cl -> bstats ));
1322+ cl -> bstats .bytes += cl -> bstats_bias .bytes ;
1323+ cl -> bstats .packets += cl -> bstats_bias .packets ;
1324+ } else {
1325+ htb_offload_aggregate_stats (q , cl );
1326+ }
1327+ }
1328+
12831329 if (gnet_stats_copy_basic (qdisc_root_sleeping_running (sch ),
12841330 d , NULL , & cl -> bstats ) < 0 ||
12851331 gnet_stats_copy_rate_est (d , & cl -> rate_est ) < 0 ||
@@ -1464,6 +1510,11 @@ static int htb_destroy_class_offload(struct Qdisc *sch, struct htb_class *cl,
14641510 WARN_ON (old != q );
14651511 }
14661512
1513+ if (cl -> parent ) {
1514+ cl -> parent -> bstats_bias .bytes += q -> bstats .bytes ;
1515+ cl -> parent -> bstats_bias .packets += q -> bstats .packets ;
1516+ }
1517+
14671518 offload_opt = (struct tc_htb_qopt_offload ) {
14681519 .command = !last_child ? TC_HTB_LEAF_DEL :
14691520 destroying ? TC_HTB_LEAF_DEL_LAST_FORCE :
@@ -1803,6 +1854,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
18031854 htb_graft_helper (dev_queue , old_q );
18041855 goto err_kill_estimator ;
18051856 }
1857+ parent -> bstats_bias .bytes += old_q -> bstats .bytes ;
1858+ parent -> bstats_bias .packets += old_q -> bstats .packets ;
18061859 qdisc_put (old_q );
18071860 }
18081861 new_q = qdisc_create_dflt (dev_queue , & pfifo_qdisc_ops ,
0 commit comments