Commit 45203a3b authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

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: default avatarEric Dumazet <edumazet@google.com>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b41abb42
...@@ -18,7 +18,7 @@ struct tcf_common { ...@@ -18,7 +18,7 @@ struct tcf_common {
struct tcf_t tcfc_tm; struct tcf_t tcfc_tm;
struct gnet_stats_basic_packed tcfc_bstats; struct gnet_stats_basic_packed tcfc_bstats;
struct gnet_stats_queue tcfc_qstats; struct gnet_stats_queue tcfc_qstats;
struct gnet_stats_rate_est tcfc_rate_est; struct gnet_stats_rate_est64 tcfc_rate_est;
spinlock_t tcfc_lock; spinlock_t tcfc_lock;
struct rcu_head tcfc_rcu; struct rcu_head tcfc_rcu;
}; };
......
...@@ -30,7 +30,7 @@ extern int gnet_stats_copy_basic(struct gnet_dump *d, ...@@ -30,7 +30,7 @@ extern int gnet_stats_copy_basic(struct gnet_dump *d,
struct gnet_stats_basic_packed *b); struct gnet_stats_basic_packed *b);
extern int gnet_stats_copy_rate_est(struct gnet_dump *d, extern int gnet_stats_copy_rate_est(struct gnet_dump *d,
const struct gnet_stats_basic_packed *b, const struct gnet_stats_basic_packed *b,
struct gnet_stats_rate_est *r); struct gnet_stats_rate_est64 *r);
extern int gnet_stats_copy_queue(struct gnet_dump *d, extern int gnet_stats_copy_queue(struct gnet_dump *d,
struct gnet_stats_queue *q); struct gnet_stats_queue *q);
extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len); 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,13 +38,13 @@ extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len);
extern int gnet_stats_finish_copy(struct gnet_dump *d); extern int gnet_stats_finish_copy(struct gnet_dump *d);
extern int gen_new_estimator(struct gnet_stats_basic_packed *bstats, extern int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
struct gnet_stats_rate_est *rate_est, struct gnet_stats_rate_est64 *rate_est,
spinlock_t *stats_lock, struct nlattr *opt); spinlock_t *stats_lock, struct nlattr *opt);
extern void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, extern void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
struct gnet_stats_rate_est *rate_est); struct gnet_stats_rate_est64 *rate_est);
extern int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, extern int gen_replace_estimator(struct gnet_stats_basic_packed *bstats,
struct gnet_stats_rate_est *rate_est, struct gnet_stats_rate_est64 *rate_est,
spinlock_t *stats_lock, struct nlattr *opt); spinlock_t *stats_lock, struct nlattr *opt);
extern bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, extern bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats,
const struct gnet_stats_rate_est *rate_est); const struct gnet_stats_rate_est64 *rate_est);
#endif #endif
...@@ -6,7 +6,7 @@ struct xt_rateest { ...@@ -6,7 +6,7 @@ struct xt_rateest {
struct gnet_stats_basic_packed bstats; struct gnet_stats_basic_packed bstats;
spinlock_t lock; spinlock_t lock;
/* keep rstats and lock on same cache line to speedup xt_rateest_mt() */ /* keep rstats and lock on same cache line to speedup xt_rateest_mt() */
struct gnet_stats_rate_est rstats; struct gnet_stats_rate_est64 rstats;
/* following fields not accessed in hot path */ /* following fields not accessed in hot path */
struct hlist_node list; struct hlist_node list;
......
...@@ -58,14 +58,12 @@ struct Qdisc { ...@@ -58,14 +58,12 @@ struct Qdisc {
* multiqueue device. * multiqueue device.
*/ */
#define TCQ_F_WARN_NONWC (1 << 16) #define TCQ_F_WARN_NONWC (1 << 16)
int padded; u32 limit;
const struct Qdisc_ops *ops; const struct Qdisc_ops *ops;
struct qdisc_size_table __rcu *stab; struct qdisc_size_table __rcu *stab;
struct list_head list; struct list_head list;
u32 handle; u32 handle;
u32 parent; u32 parent;
atomic_t refcnt;
struct gnet_stats_rate_est rate_est;
int (*reshape_fail)(struct sk_buff *skb, int (*reshape_fail)(struct sk_buff *skb,
struct Qdisc *q); struct Qdisc *q);
...@@ -76,8 +74,9 @@ struct Qdisc { ...@@ -76,8 +74,9 @@ struct Qdisc {
*/ */
struct Qdisc *__parent; struct Qdisc *__parent;
struct netdev_queue *dev_queue; struct netdev_queue *dev_queue;
struct Qdisc *next_sched;
struct gnet_stats_rate_est64 rate_est;
struct Qdisc *next_sched;
struct sk_buff *gso_skb; struct sk_buff *gso_skb;
/* /*
* For performance sake on SMP, we put highly modified fields at the end * For performance sake on SMP, we put highly modified fields at the end
...@@ -88,8 +87,10 @@ struct Qdisc { ...@@ -88,8 +87,10 @@ struct Qdisc {
unsigned int __state; unsigned int __state;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct rcu_head rcu_head; struct rcu_head rcu_head;
spinlock_t busylock; int padded;
u32 limit; atomic_t refcnt;
spinlock_t busylock ____cacheline_aligned_in_smp;
}; };
static inline bool qdisc_is_running(const struct Qdisc *qdisc) static inline bool qdisc_is_running(const struct Qdisc *qdisc)
......
...@@ -9,6 +9,7 @@ enum { ...@@ -9,6 +9,7 @@ enum {
TCA_STATS_RATE_EST, TCA_STATS_RATE_EST,
TCA_STATS_QUEUE, TCA_STATS_QUEUE,
TCA_STATS_APP, TCA_STATS_APP,
TCA_STATS_RATE_EST64,
__TCA_STATS_MAX, __TCA_STATS_MAX,
}; };
#define TCA_STATS_MAX (__TCA_STATS_MAX - 1) #define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
...@@ -37,6 +38,16 @@ struct gnet_stats_rate_est { ...@@ -37,6 +38,16 @@ struct gnet_stats_rate_est {
__u32 pps; __u32 pps;
}; };
/**
* struct gnet_stats_rate_est64 - rate estimator
* @bps: current byte rate
* @pps: current packet rate
*/
struct gnet_stats_rate_est64 {
__u64 bps;
__u64 pps;
};
/** /**
* struct gnet_stats_queue - queuing statistics * struct gnet_stats_queue - queuing statistics
* @qlen: queue length * @qlen: queue length
......
...@@ -82,7 +82,7 @@ struct gen_estimator ...@@ -82,7 +82,7 @@ struct gen_estimator
{ {
struct list_head list; struct list_head list;
struct gnet_stats_basic_packed *bstats; struct gnet_stats_basic_packed *bstats;
struct gnet_stats_rate_est *rate_est; struct gnet_stats_rate_est64 *rate_est;
spinlock_t *stats_lock; spinlock_t *stats_lock;
int ewma_log; int ewma_log;
u64 last_bytes; u64 last_bytes;
...@@ -167,7 +167,7 @@ static void gen_add_node(struct gen_estimator *est) ...@@ -167,7 +167,7 @@ static void gen_add_node(struct gen_estimator *est)
static static
struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats, struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats,
const struct gnet_stats_rate_est *rate_est) const struct gnet_stats_rate_est64 *rate_est)
{ {
struct rb_node *p = est_root.rb_node; struct rb_node *p = est_root.rb_node;
...@@ -203,7 +203,7 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats ...@@ -203,7 +203,7 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats
* *
*/ */
int gen_new_estimator(struct gnet_stats_basic_packed *bstats, int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
struct gnet_stats_rate_est *rate_est, struct gnet_stats_rate_est64 *rate_est,
spinlock_t *stats_lock, spinlock_t *stats_lock,
struct nlattr *opt) struct nlattr *opt)
{ {
...@@ -258,7 +258,7 @@ EXPORT_SYMBOL(gen_new_estimator); ...@@ -258,7 +258,7 @@ EXPORT_SYMBOL(gen_new_estimator);
* Note : Caller should respect an RCU grace period before freeing stats_lock * Note : Caller should respect an RCU grace period before freeing stats_lock
*/ */
void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
struct gnet_stats_rate_est *rate_est) struct gnet_stats_rate_est64 *rate_est)
{ {
struct gen_estimator *e; struct gen_estimator *e;
...@@ -290,7 +290,7 @@ EXPORT_SYMBOL(gen_kill_estimator); ...@@ -290,7 +290,7 @@ EXPORT_SYMBOL(gen_kill_estimator);
* Returns 0 on success or a negative error code. * Returns 0 on success or a negative error code.
*/ */
int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, int gen_replace_estimator(struct gnet_stats_basic_packed *bstats,
struct gnet_stats_rate_est *rate_est, struct gnet_stats_rate_est64 *rate_est,
spinlock_t *stats_lock, struct nlattr *opt) spinlock_t *stats_lock, struct nlattr *opt)
{ {
gen_kill_estimator(bstats, rate_est); gen_kill_estimator(bstats, rate_est);
...@@ -306,7 +306,7 @@ EXPORT_SYMBOL(gen_replace_estimator); ...@@ -306,7 +306,7 @@ EXPORT_SYMBOL(gen_replace_estimator);
* Returns true if estimator is active, and false if not. * Returns true if estimator is active, and false if not.
*/ */
bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats,
const struct gnet_stats_rate_est *rate_est) const struct gnet_stats_rate_est64 *rate_est)
{ {
bool res; bool res;
......
...@@ -143,18 +143,30 @@ EXPORT_SYMBOL(gnet_stats_copy_basic); ...@@ -143,18 +143,30 @@ EXPORT_SYMBOL(gnet_stats_copy_basic);
int int
gnet_stats_copy_rate_est(struct gnet_dump *d, gnet_stats_copy_rate_est(struct gnet_dump *d,
const struct gnet_stats_basic_packed *b, const struct gnet_stats_basic_packed *b,
struct gnet_stats_rate_est *r) struct gnet_stats_rate_est64 *r)
{ {
struct gnet_stats_rate_est est;
int res;
if (b && !gen_estimator_active(b, r)) if (b && !gen_estimator_active(b, r))
return 0; return 0;
est.bps = min_t(u64, UINT_MAX, r->bps);
/* we have some time before reaching 2^32 packets per second */
est.pps = r->pps;
if (d->compat_tc_stats) { if (d->compat_tc_stats) {
d->tc_stats.bps = r->bps; d->tc_stats.bps = est.bps;
d->tc_stats.pps = r->pps; d->tc_stats.pps = est.pps;
} }
if (d->tail) if (d->tail) {
return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r)); res = gnet_stats_copy(d, TCA_STATS_RATE_EST, &est, sizeof(est));
if (res < 0 || est.bps == r->bps)
return res;
/* emit 64bit stats only if needed */
return gnet_stats_copy(d, TCA_STATS_RATE_EST64, r, sizeof(*r));
}
return 0; return 0;
} }
......
...@@ -18,7 +18,7 @@ static bool ...@@ -18,7 +18,7 @@ static bool
xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par)
{ {
const struct xt_rateest_match_info *info = par->matchinfo; const struct xt_rateest_match_info *info = par->matchinfo;
struct gnet_stats_rate_est *r; struct gnet_stats_rate_est64 *r;
u_int32_t bps1, bps2, pps1, pps2; u_int32_t bps1, bps2, pps1, pps2;
bool ret = true; bool ret = true;
......
...@@ -130,7 +130,7 @@ struct cbq_class { ...@@ -130,7 +130,7 @@ struct cbq_class {
psched_time_t penalized; psched_time_t penalized;
struct gnet_stats_basic_packed bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est64 rate_est;
struct tc_cbq_xstats xstats; struct tc_cbq_xstats xstats;
struct tcf_proto *filter_list; struct tcf_proto *filter_list;
......
...@@ -25,7 +25,7 @@ struct drr_class { ...@@ -25,7 +25,7 @@ struct drr_class {
struct gnet_stats_basic_packed bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est64 rate_est;
struct list_head alist; struct list_head alist;
struct Qdisc *qdisc; struct Qdisc *qdisc;
......
...@@ -114,7 +114,7 @@ struct hfsc_class { ...@@ -114,7 +114,7 @@ struct hfsc_class {
struct gnet_stats_basic_packed bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est64 rate_est;
unsigned int level; /* class level in hierarchy */ unsigned int level; /* class level in hierarchy */
struct tcf_proto *filter_list; /* filter list */ struct tcf_proto *filter_list; /* filter list */
unsigned int filter_cnt; /* filter count */ unsigned int filter_cnt; /* filter count */
......
...@@ -78,7 +78,7 @@ struct htb_class { ...@@ -78,7 +78,7 @@ struct htb_class {
/* general class parameters */ /* general class parameters */
struct gnet_stats_basic_packed bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est64 rate_est;
struct tc_htb_xstats xstats; /* our special stats */ struct tc_htb_xstats xstats; /* our special stats */
int refcnt; /* usage count of this class */ int refcnt; /* usage count of this class */
......
...@@ -138,7 +138,7 @@ struct qfq_class { ...@@ -138,7 +138,7 @@ struct qfq_class {
struct gnet_stats_basic_packed bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est64 rate_est;
struct Qdisc *qdisc; struct Qdisc *qdisc;
struct list_head alist; /* Link for active-classes list. */ struct list_head alist; /* Link for active-classes list. */
struct qfq_aggregate *agg; /* Parent aggregate. */ struct qfq_aggregate *agg; /* Parent aggregate. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment