diff options
author | Eric Dumazet <edumazet@google.com> | 2013-06-06 11:43:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-11 05:51:03 -0400 |
commit | 45203a3b380cee28f570475c0d28c169f908c209 (patch) | |
tree | 9d9b00da9accbc0ea01c91c206cb86a2f9dd7609 | |
parent | b41abb42bf62a85a32c41dab873220598a6ee266 (diff) |
net_sched: add 64bit rate estimators
struct gnet_stats_rate_est contains u32 fields, so the bytes per second
field can wrap at 34360Mbit.
Add a new gnet_stats_rate_est64 structure to get 64bit bps/pps fields,
and switch the kernel to use this structure natively.
This structure is dumped to user space as a new attribute :
TCA_STATS_RATE_EST64
Old tc command will now display the capped bps (to 34360Mbit), instead
of wrapped values, and updated tc command will display correct
information.
Old tc command output, after patch :
eric:~# tc -s -d qd sh dev lo
qdisc pfifo 8001: root refcnt 2 limit 1000p
Sent 80868245400 bytes 1978837 pkt (dropped 0, overlimits 0 requeues 0)
rate 34360Mbit 189696pps backlog 0b 0p requeues 0
This patch carefully reorganizes "struct Qdisc" layout to get optimal
performance on SMP.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/act_api.h | 2 | ||||
-rw-r--r-- | include/net/gen_stats.h | 10 | ||||
-rw-r--r-- | include/net/netfilter/xt_rateest.h | 2 | ||||
-rw-r--r-- | include/net/sch_generic.h | 13 | ||||
-rw-r--r-- | include/uapi/linux/gen_stats.h | 11 | ||||
-rw-r--r-- | net/core/gen_estimator.c | 12 | ||||
-rw-r--r-- | net/core/gen_stats.c | 22 | ||||
-rw-r--r-- | net/netfilter/xt_rateest.c | 2 | ||||
-rw-r--r-- | net/sched/sch_cbq.c | 2 | ||||
-rw-r--r-- | net/sched/sch_drr.c | 2 | ||||
-rw-r--r-- | net/sched/sch_hfsc.c | 2 | ||||
-rw-r--r-- | net/sched/sch_htb.c | 2 | ||||
-rw-r--r-- | net/sched/sch_qfq.c | 2 |
13 files changed, 54 insertions, 30 deletions
diff --git a/include/net/act_api.h b/include/net/act_api.h index 06ef7e926a66..b8ffac7b6bab 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h | |||
@@ -18,7 +18,7 @@ struct tcf_common { | |||
18 | struct tcf_t tcfc_tm; | 18 | struct tcf_t tcfc_tm; |
19 | struct gnet_stats_basic_packed tcfc_bstats; | 19 | struct gnet_stats_basic_packed tcfc_bstats; |
20 | struct gnet_stats_queue tcfc_qstats; | 20 | struct gnet_stats_queue tcfc_qstats; |
21 | struct gnet_stats_rate_est tcfc_rate_est; | 21 | struct gnet_stats_rate_est64 tcfc_rate_est; |
22 | spinlock_t tcfc_lock; | 22 | spinlock_t tcfc_lock; |
23 | struct rcu_head tcfc_rcu; | 23 | struct rcu_head tcfc_rcu; |
24 | }; | 24 | }; |
diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h index a79b6cfb02a8..cf8439ba4d11 100644 --- a/include/net/gen_stats.h +++ b/include/net/gen_stats.h | |||
@@ -30,7 +30,7 @@ extern int gnet_stats_copy_basic(struct gnet_dump *d, | |||
30 | struct gnet_stats_basic_packed *b); | 30 | struct gnet_stats_basic_packed *b); |
31 | extern int gnet_stats_copy_rate_est(struct gnet_dump *d, | 31 | extern int gnet_stats_copy_rate_est(struct gnet_dump *d, |
32 | const struct gnet_stats_basic_packed *b, | 32 | const struct gnet_stats_basic_packed *b, |
33 | struct gnet_stats_rate_est *r); | 33 | struct gnet_stats_rate_est64 *r); |
34 | extern int gnet_stats_copy_queue(struct gnet_dump *d, | 34 | extern int gnet_stats_copy_queue(struct gnet_dump *d, |
35 | struct gnet_stats_queue *q); | 35 | struct gnet_stats_queue *q); |
36 | extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len); | 36 | extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len); |
@@ -38,13 +38,13 @@ extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len); | |||
38 | extern int gnet_stats_finish_copy(struct gnet_dump *d); | 38 | extern int gnet_stats_finish_copy(struct gnet_dump *d); |
39 | 39 | ||
40 | extern int gen_new_estimator(struct gnet_stats_basic_packed *bstats, | 40 | extern int gen_new_estimator(struct gnet_stats_basic_packed *bstats, |
41 | struct gnet_stats_rate_est *rate_est, | 41 | struct gnet_stats_rate_est64 *rate_est, |
42 | spinlock_t *stats_lock, struct nlattr *opt); | 42 | spinlock_t *stats_lock, struct nlattr *opt); |
43 | extern void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, | 43 | extern void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, |
44 | struct gnet_stats_rate_est *rate_est); | 44 | struct gnet_stats_rate_est64 *rate_est); |
45 | extern int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, | 45 | extern int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, |
46 | struct gnet_stats_rate_est *rate_est, | 46 | struct gnet_stats_rate_est64 *rate_est, |
47 | spinlock_t *stats_lock, struct nlattr *opt); | 47 | spinlock_t *stats_lock, struct nlattr *opt); |
48 | extern bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, | 48 | extern bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, |
49 | const struct gnet_stats_rate_est *rate_est); | 49 | const struct gnet_stats_rate_est64 *rate_est); |
50 | #endif | 50 | #endif |
diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h index 5a2978d1cb22..495c71f66e7e 100644 --- a/include/net/netfilter/xt_rateest.h +++ b/include/net/netfilter/xt_rateest.h | |||
@@ -6,7 +6,7 @@ struct xt_rateest { | |||
6 | struct gnet_stats_basic_packed bstats; | 6 | struct gnet_stats_basic_packed bstats; |
7 | spinlock_t lock; | 7 | spinlock_t lock; |
8 | /* keep rstats and lock on same cache line to speedup xt_rateest_mt() */ | 8 | /* keep rstats and lock on same cache line to speedup xt_rateest_mt() */ |
9 | struct gnet_stats_rate_est rstats; | 9 | struct gnet_stats_rate_est64 rstats; |
10 | 10 | ||
11 | /* following fields not accessed in hot path */ | 11 | /* following fields not accessed in hot path */ |
12 | struct hlist_node list; | 12 | struct hlist_node list; |
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index e7f4e21cc3e1..df5676029827 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h | |||
@@ -58,14 +58,12 @@ struct Qdisc { | |||
58 | * multiqueue device. | 58 | * multiqueue device. |
59 | */ | 59 | */ |
60 | #define TCQ_F_WARN_NONWC (1 << 16) | 60 | #define TCQ_F_WARN_NONWC (1 << 16) |
61 | int padded; | 61 | u32 limit; |
62 | const struct Qdisc_ops *ops; | 62 | const struct Qdisc_ops *ops; |
63 | struct qdisc_size_table __rcu *stab; | 63 | struct qdisc_size_table __rcu *stab; |
64 | struct list_head list; | 64 | struct list_head list; |
65 | u32 handle; | 65 | u32 handle; |
66 | u32 parent; | 66 | u32 parent; |
67 | atomic_t refcnt; | ||
68 | struct gnet_stats_rate_est rate_est; | ||
69 | int (*reshape_fail)(struct sk_buff *skb, | 67 | int (*reshape_fail)(struct sk_buff *skb, |
70 | struct Qdisc *q); | 68 | struct Qdisc *q); |
71 | 69 | ||
@@ -76,8 +74,9 @@ struct Qdisc { | |||
76 | */ | 74 | */ |
77 | struct Qdisc *__parent; | 75 | struct Qdisc *__parent; |
78 | struct netdev_queue *dev_queue; | 76 | struct netdev_queue *dev_queue; |
79 | struct Qdisc *next_sched; | ||
80 | 77 | ||
78 | struct gnet_stats_rate_est64 rate_est; | ||
79 | struct Qdisc *next_sched; | ||
81 | struct sk_buff *gso_skb; | 80 | struct sk_buff *gso_skb; |
82 | /* | 81 | /* |
83 | * For performance sake on SMP, we put highly modified fields at the end | 82 | * For performance sake on SMP, we put highly modified fields at the end |
@@ -88,8 +87,10 @@ struct Qdisc { | |||
88 | unsigned int __state; | 87 | unsigned int __state; |
89 | struct gnet_stats_queue qstats; | 88 | struct gnet_stats_queue qstats; |
90 | struct rcu_head rcu_head; | 89 | struct rcu_head rcu_head; |
91 | spinlock_t busylock; | 90 | int padded; |
92 | u32 limit; | 91 | atomic_t refcnt; |
92 | |||
93 | spinlock_t busylock ____cacheline_aligned_in_smp; | ||
93 | }; | 94 | }; |
94 | 95 | ||
95 | static inline bool qdisc_is_running(const struct Qdisc *qdisc) | 96 | static inline bool qdisc_is_running(const struct Qdisc *qdisc) |
diff --git a/include/uapi/linux/gen_stats.h b/include/uapi/linux/gen_stats.h index 552c8a0a12d1..6487317ea619 100644 --- a/include/uapi/linux/gen_stats.h +++ b/include/uapi/linux/gen_stats.h | |||
@@ -9,6 +9,7 @@ enum { | |||
9 | TCA_STATS_RATE_EST, | 9 | TCA_STATS_RATE_EST, |
10 | TCA_STATS_QUEUE, | 10 | TCA_STATS_QUEUE, |
11 | TCA_STATS_APP, | 11 | TCA_STATS_APP, |
12 | TCA_STATS_RATE_EST64, | ||
12 | __TCA_STATS_MAX, | 13 | __TCA_STATS_MAX, |
13 | }; | 14 | }; |
14 | #define TCA_STATS_MAX (__TCA_STATS_MAX - 1) | 15 | #define TCA_STATS_MAX (__TCA_STATS_MAX - 1) |
@@ -38,6 +39,16 @@ struct gnet_stats_rate_est { | |||
38 | }; | 39 | }; |
39 | 40 | ||
40 | /** | 41 | /** |
42 | * struct gnet_stats_rate_est64 - rate estimator | ||
43 | * @bps: current byte rate | ||
44 | * @pps: current packet rate | ||
45 | */ | ||
46 | struct gnet_stats_rate_est64 { | ||
47 | __u64 bps; | ||
48 | __u64 pps; | ||
49 | }; | ||
50 | |||
51 | /** | ||
41 | * struct gnet_stats_queue - queuing statistics | 52 | * struct gnet_stats_queue - queuing statistics |
42 | * @qlen: queue length | 53 | * @qlen: queue length |
43 | * @backlog: backlog size of queue | 54 | * @backlog: backlog size of queue |
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index d9d198aa9fed..6b5b6e7013ca 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c | |||
@@ -82,7 +82,7 @@ struct gen_estimator | |||
82 | { | 82 | { |
83 | struct list_head list; | 83 | struct list_head list; |
84 | struct gnet_stats_basic_packed *bstats; | 84 | struct gnet_stats_basic_packed *bstats; |
85 | struct gnet_stats_rate_est *rate_est; | 85 | struct gnet_stats_rate_est64 *rate_est; |
86 | spinlock_t *stats_lock; | 86 | spinlock_t *stats_lock; |
87 | int ewma_log; | 87 | int ewma_log; |
88 | u64 last_bytes; | 88 | u64 last_bytes; |
@@ -167,7 +167,7 @@ static void gen_add_node(struct gen_estimator *est) | |||
167 | 167 | ||
168 | static | 168 | static |
169 | struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats, | 169 | struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats, |
170 | const struct gnet_stats_rate_est *rate_est) | 170 | const struct gnet_stats_rate_est64 *rate_est) |
171 | { | 171 | { |
172 | struct rb_node *p = est_root.rb_node; | 172 | struct rb_node *p = est_root.rb_node; |
173 | 173 | ||
@@ -203,7 +203,7 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats | |||
203 | * | 203 | * |
204 | */ | 204 | */ |
205 | int gen_new_estimator(struct gnet_stats_basic_packed *bstats, | 205 | int gen_new_estimator(struct gnet_stats_basic_packed *bstats, |
206 | struct gnet_stats_rate_est *rate_est, | 206 | struct gnet_stats_rate_est64 *rate_est, |
207 | spinlock_t *stats_lock, | 207 | spinlock_t *stats_lock, |
208 | struct nlattr *opt) | 208 | struct nlattr *opt) |
209 | { | 209 | { |
@@ -258,7 +258,7 @@ EXPORT_SYMBOL(gen_new_estimator); | |||
258 | * Note : Caller should respect an RCU grace period before freeing stats_lock | 258 | * Note : Caller should respect an RCU grace period before freeing stats_lock |
259 | */ | 259 | */ |
260 | void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, | 260 | void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, |
261 | struct gnet_stats_rate_est *rate_est) | 261 | struct gnet_stats_rate_est64 *rate_est) |
262 | { | 262 | { |
263 | struct gen_estimator *e; | 263 | struct gen_estimator *e; |
264 | 264 | ||
@@ -290,7 +290,7 @@ EXPORT_SYMBOL(gen_kill_estimator); | |||
290 | * Returns 0 on success or a negative error code. | 290 | * Returns 0 on success or a negative error code. |
291 | */ | 291 | */ |
292 | int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, | 292 | int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, |
293 | struct gnet_stats_rate_est *rate_est, | 293 | struct gnet_stats_rate_est64 *rate_est, |
294 | spinlock_t *stats_lock, struct nlattr *opt) | 294 | spinlock_t *stats_lock, struct nlattr *opt) |
295 | { | 295 | { |
296 | gen_kill_estimator(bstats, rate_est); | 296 | gen_kill_estimator(bstats, rate_est); |
@@ -306,7 +306,7 @@ EXPORT_SYMBOL(gen_replace_estimator); | |||
306 | * Returns true if estimator is active, and false if not. | 306 | * Returns true if estimator is active, and false if not. |
307 | */ | 307 | */ |
308 | bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, | 308 | bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, |
309 | const struct gnet_stats_rate_est *rate_est) | 309 | const struct gnet_stats_rate_est64 *rate_est) |
310 | { | 310 | { |
311 | bool res; | 311 | bool res; |
312 | 312 | ||
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index ddedf211e588..9d3d9e78397b 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c | |||
@@ -143,18 +143,30 @@ EXPORT_SYMBOL(gnet_stats_copy_basic); | |||
143 | int | 143 | int |
144 | gnet_stats_copy_rate_est(struct gnet_dump *d, | 144 | gnet_stats_copy_rate_est(struct gnet_dump *d, |
145 | const struct gnet_stats_basic_packed *b, | 145 | const struct gnet_stats_basic_packed *b, |
146 | struct gnet_stats_rate_est *r) | 146 | struct gnet_stats_rate_est64 *r) |
147 | { | 147 | { |
148 | struct gnet_stats_rate_est est; | ||
149 | int res; | ||
150 | |||
148 | if (b && !gen_estimator_active(b, r)) | 151 | if (b && !gen_estimator_active(b, r)) |
149 | return 0; | 152 | return 0; |
150 | 153 | ||
154 | est.bps = min_t(u64, UINT_MAX, r->bps); | ||
155 | /* we have some time before reaching 2^32 packets per second */ | ||
156 | est.pps = r->pps; | ||
157 | |||
151 | if (d->compat_tc_stats) { | 158 | if (d->compat_tc_stats) { |
152 | d->tc_stats.bps = r->bps; | 159 | d->tc_stats.bps = est.bps; |
153 | d->tc_stats.pps = r->pps; | 160 | d->tc_stats.pps = est.pps; |
154 | } | 161 | } |
155 | 162 | ||
156 | if (d->tail) | 163 | if (d->tail) { |
157 | return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r)); | 164 | res = gnet_stats_copy(d, TCA_STATS_RATE_EST, &est, sizeof(est)); |
165 | if (res < 0 || est.bps == r->bps) | ||
166 | return res; | ||
167 | /* emit 64bit stats only if needed */ | ||
168 | return gnet_stats_copy(d, TCA_STATS_RATE_EST64, r, sizeof(*r)); | ||
169 | } | ||
158 | 170 | ||
159 | return 0; | 171 | return 0; |
160 | } | 172 | } |
diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c index ed0db15ab00e..7720b036d76a 100644 --- a/net/netfilter/xt_rateest.c +++ b/net/netfilter/xt_rateest.c | |||
@@ -18,7 +18,7 @@ static bool | |||
18 | xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) | 18 | xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) |
19 | { | 19 | { |
20 | const struct xt_rateest_match_info *info = par->matchinfo; | 20 | const struct xt_rateest_match_info *info = par->matchinfo; |
21 | struct gnet_stats_rate_est *r; | 21 | struct gnet_stats_rate_est64 *r; |
22 | u_int32_t bps1, bps2, pps1, pps2; | 22 | u_int32_t bps1, bps2, pps1, pps2; |
23 | bool ret = true; | 23 | bool ret = true; |
24 | 24 | ||
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 1bc210ffcba2..71a568862557 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c | |||
@@ -130,7 +130,7 @@ struct cbq_class { | |||
130 | psched_time_t penalized; | 130 | psched_time_t penalized; |
131 | struct gnet_stats_basic_packed bstats; | 131 | struct gnet_stats_basic_packed bstats; |
132 | struct gnet_stats_queue qstats; | 132 | struct gnet_stats_queue qstats; |
133 | struct gnet_stats_rate_est rate_est; | 133 | struct gnet_stats_rate_est64 rate_est; |
134 | struct tc_cbq_xstats xstats; | 134 | struct tc_cbq_xstats xstats; |
135 | 135 | ||
136 | struct tcf_proto *filter_list; | 136 | struct tcf_proto *filter_list; |
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 759b308d1a8d..8302717ea303 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c | |||
@@ -25,7 +25,7 @@ struct drr_class { | |||
25 | 25 | ||
26 | struct gnet_stats_basic_packed bstats; | 26 | struct gnet_stats_basic_packed bstats; |
27 | struct gnet_stats_queue qstats; | 27 | struct gnet_stats_queue qstats; |
28 | struct gnet_stats_rate_est rate_est; | 28 | struct gnet_stats_rate_est64 rate_est; |
29 | struct list_head alist; | 29 | struct list_head alist; |
30 | struct Qdisc *qdisc; | 30 | struct Qdisc *qdisc; |
31 | 31 | ||
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 9facea03faeb..c4075610502c 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c | |||
@@ -114,7 +114,7 @@ struct hfsc_class { | |||
114 | 114 | ||
115 | struct gnet_stats_basic_packed bstats; | 115 | struct gnet_stats_basic_packed bstats; |
116 | struct gnet_stats_queue qstats; | 116 | struct gnet_stats_queue qstats; |
117 | struct gnet_stats_rate_est rate_est; | 117 | struct gnet_stats_rate_est64 rate_est; |
118 | unsigned int level; /* class level in hierarchy */ | 118 | unsigned int level; /* class level in hierarchy */ |
119 | struct tcf_proto *filter_list; /* filter list */ | 119 | struct tcf_proto *filter_list; /* filter list */ |
120 | unsigned int filter_cnt; /* filter count */ | 120 | unsigned int filter_cnt; /* filter count */ |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index adaedd79389c..162fb800754c 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -78,7 +78,7 @@ struct htb_class { | |||
78 | /* general class parameters */ | 78 | /* general class parameters */ |
79 | struct gnet_stats_basic_packed bstats; | 79 | struct gnet_stats_basic_packed bstats; |
80 | struct gnet_stats_queue qstats; | 80 | struct gnet_stats_queue qstats; |
81 | struct gnet_stats_rate_est rate_est; | 81 | struct gnet_stats_rate_est64 rate_est; |
82 | struct tc_htb_xstats xstats; /* our special stats */ | 82 | struct tc_htb_xstats xstats; /* our special stats */ |
83 | int refcnt; /* usage count of this class */ | 83 | int refcnt; /* usage count of this class */ |
84 | 84 | ||
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index d51852bba01c..7c195d972bf0 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c | |||
@@ -138,7 +138,7 @@ struct qfq_class { | |||
138 | 138 | ||
139 | struct gnet_stats_basic_packed bstats; | 139 | struct gnet_stats_basic_packed bstats; |
140 | struct gnet_stats_queue qstats; | 140 | struct gnet_stats_queue qstats; |
141 | struct gnet_stats_rate_est rate_est; | 141 | struct gnet_stats_rate_est64 rate_est; |
142 | struct Qdisc *qdisc; | 142 | struct Qdisc *qdisc; |
143 | struct list_head alist; /* Link for active-classes list. */ | 143 | struct list_head alist; /* Link for active-classes list. */ |
144 | struct qfq_aggregate *agg; /* Parent aggregate. */ | 144 | struct qfq_aggregate *agg; /* Parent aggregate. */ |