2005-04-17 02:20:36 +04:00
/*
* net / core / gen_stats . c
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* Authors : Thomas Graf < tgraf @ suug . ch >
* Jamal Hadi Salim
* Alexey Kuznetsov , < kuznet @ ms2 . inr . ac . ru >
*
* See Documentation / networking / gen_stats . txt
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/socket.h>
# include <linux/rtnetlink.h>
# include <linux/gen_stats.h>
2008-01-23 09:11:17 +03:00
# include <net/netlink.h>
2005-04-17 02:20:36 +04:00
# include <net/gen_stats.h>
static inline int
gnet_stats_copy ( struct gnet_dump * d , int type , void * buf , int size )
{
2012-04-02 04:47:35 +04:00
if ( nla_put ( d - > skb , type , size , buf ) )
goto nla_put_failure ;
2005-04-17 02:20:36 +04:00
return 0 ;
2008-01-23 09:11:17 +03:00
nla_put_failure :
2015-02-14 01:47:05 +03:00
kfree ( d - > xstats ) ;
d - > xstats = NULL ;
d - > xstats_len = 0 ;
2005-04-17 02:20:36 +04:00
spin_unlock_bh ( d - > lock ) ;
return - 1 ;
}
/**
* gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
* @ skb : socket buffer to put statistics TLVs into
* @ type : TLV type for top level statistic TLV
* @ tc_stats_type : TLV type for backward compatibility struct tc_stats TLV
* @ xstats_type : TLV type for backward compatibility xstats TLV
* @ lock : statistics lock
* @ d : dumping handle
*
* Initializes the dumping handle , grabs the statistic lock and appends
* an empty TLV header to the socket buffer for use a container for all
* other statistic TLVS .
*
* The dumping handle is marked to be in backward compatibility mode telling
* all gnet_stats_copy_XXX ( ) functions to fill a local copy of struct tc_stats .
*
* Returns 0 on success or - 1 if the room in the socket buffer was not sufficient .
*/
int
gnet_stats_start_copy_compat ( struct sk_buff * skb , int type , int tc_stats_type ,
int xstats_type , spinlock_t * lock , struct gnet_dump * d )
2008-01-02 08:58:02 +03:00
__acquires ( lock )
2005-04-17 02:20:36 +04:00
{
memset ( d , 0 , sizeof ( * d ) ) ;
2007-02-09 17:24:36 +03:00
2005-04-17 02:20:36 +04:00
spin_lock_bh ( lock ) ;
d - > lock = lock ;
if ( type )
2008-01-23 09:11:17 +03:00
d - > tail = ( struct nlattr * ) skb_tail_pointer ( skb ) ;
2005-04-17 02:20:36 +04:00
d - > skb = skb ;
d - > compat_tc_stats = tc_stats_type ;
d - > compat_xstats = xstats_type ;
if ( d - > tail )
return gnet_stats_copy ( d , type , NULL , 0 ) ;
return 0 ;
}
2010-07-10 01:22:04 +04:00
EXPORT_SYMBOL ( gnet_stats_start_copy_compat ) ;
2005-04-17 02:20:36 +04:00
/**
* gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
* @ skb : socket buffer to put statistics TLVs into
* @ type : TLV type for top level statistic TLV
* @ lock : statistics lock
* @ d : dumping handle
*
* Initializes the dumping handle , grabs the statistic lock and appends
* an empty TLV header to the socket buffer for use a container for all
* other statistic TLVS .
*
* Returns 0 on success or - 1 if the room in the socket buffer was not sufficient .
*/
int
gnet_stats_start_copy ( struct sk_buff * skb , int type , spinlock_t * lock ,
struct gnet_dump * d )
{
return gnet_stats_start_copy_compat ( skb , type , 0 , 0 , lock , d ) ;
}
2010-07-10 01:22:04 +04:00
EXPORT_SYMBOL ( gnet_stats_start_copy ) ;
2005-04-17 02:20:36 +04:00
2014-09-28 22:52:56 +04:00
static void
__gnet_stats_copy_basic_cpu ( struct gnet_stats_basic_packed * bstats ,
struct gnet_stats_basic_cpu __percpu * cpu )
{
int i ;
for_each_possible_cpu ( i ) {
struct gnet_stats_basic_cpu * bcpu = per_cpu_ptr ( cpu , i ) ;
unsigned int start ;
2014-10-07 04:01:33 +04:00
u64 bytes ;
u32 packets ;
2014-09-28 22:52:56 +04:00
do {
start = u64_stats_fetch_begin_irq ( & bcpu - > syncp ) ;
bytes = bcpu - > bstats . bytes ;
packets = bcpu - > bstats . packets ;
} while ( u64_stats_fetch_retry_irq ( & bcpu - > syncp , start ) ) ;
2014-10-07 04:01:33 +04:00
bstats - > bytes + = bytes ;
bstats - > packets + = packets ;
2014-09-28 22:52:56 +04:00
}
}
void
__gnet_stats_copy_basic ( struct gnet_stats_basic_packed * bstats ,
struct gnet_stats_basic_cpu __percpu * cpu ,
struct gnet_stats_basic_packed * b )
{
if ( cpu ) {
__gnet_stats_copy_basic_cpu ( bstats , cpu ) ;
} else {
bstats - > bytes = b - > bytes ;
bstats - > packets = b - > packets ;
}
}
EXPORT_SYMBOL ( __gnet_stats_copy_basic ) ;
2005-04-17 02:20:36 +04:00
/**
* gnet_stats_copy_basic - copy basic statistics into statistic TLV
* @ d : dumping handle
2016-03-20 00:19:55 +03:00
* @ cpu : copy statistic per cpu
2005-04-17 02:20:36 +04:00
* @ b : basic statistics
*
* Appends the basic statistics to the top level TLV created by
* gnet_stats_start_copy ( ) .
*
* Returns 0 on success or - 1 with the statistic lock released
* if the room in the socket buffer was not sufficient .
*/
int
2014-09-28 22:52:56 +04:00
gnet_stats_copy_basic ( struct gnet_dump * d ,
struct gnet_stats_basic_cpu __percpu * cpu ,
struct gnet_stats_basic_packed * b )
2005-04-17 02:20:36 +04:00
{
2014-09-28 22:52:56 +04:00
struct gnet_stats_basic_packed bstats = { 0 } ;
__gnet_stats_copy_basic ( & bstats , cpu , b ) ;
2005-04-17 02:20:36 +04:00
if ( d - > compat_tc_stats ) {
2014-09-28 22:52:56 +04:00
d - > tc_stats . bytes = bstats . bytes ;
d - > tc_stats . packets = bstats . packets ;
2005-04-17 02:20:36 +04:00
}
2009-08-16 13:36:49 +04:00
if ( d - > tail ) {
struct gnet_stats_basic sb ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:36:49 +04:00
memset ( & sb , 0 , sizeof ( sb ) ) ;
2014-09-28 22:52:56 +04:00
sb . bytes = bstats . bytes ;
sb . packets = bstats . packets ;
2009-08-16 13:36:49 +04:00
return gnet_stats_copy ( d , TCA_STATS_BASIC , & sb , sizeof ( sb ) ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-07-10 01:22:04 +04:00
EXPORT_SYMBOL ( gnet_stats_copy_basic ) ;
2005-04-17 02:20:36 +04:00
/**
* gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
* @ d : dumping handle
pkt_sched: gen_estimator: Dont report fake rate estimators
Jarek Poplawski a écrit :
>
>
> Hmm... So you made me to do some "real" work here, and guess what?:
> there is one serious checkpatch warning! ;-) Plus, this new parameter
> should be added to the function description. Otherwise:
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
>
> Thanks,
> Jarek P.
>
> PS: I guess full "Don't" would show we really mean it...
Okay :) Here is the last round, before the night !
Thanks again
[RFC] pkt_sched: gen_estimator: Don't report fake rate estimators
We currently send TCA_STATS_RATE_EST elements to netlink users, even if no estimator
is running.
# tc -s -d qdisc
qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 112833764978 bytes 1495081739 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
User has no way to tell if the "rate 0bit 0pps" is a real estimation, or a fake
one (because no estimator is active)
After this patch, tc command output is :
$ tc -s -d qdisc
qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 561075 bytes 1196 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
We add a parameter to gnet_stats_copy_rate_est() function so that
it can use gen_estimator_active(bstats, r), as suggested by Jarek.
This parameter can be NULL if check is not necessary, (htb for
example has a mandatory rate estimator)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-10-02 14:32:18 +04:00
* @ b : basic statistics
2005-04-17 02:20:36 +04:00
* @ r : rate estimator statistics
*
* Appends the rate estimator statistics to the top level TLV created by
* gnet_stats_start_copy ( ) .
*
* Returns 0 on success or - 1 with the statistic lock released
* if the room in the socket buffer was not sufficient .
*/
int
pkt_sched: gen_estimator: Dont report fake rate estimators
Jarek Poplawski a écrit :
>
>
> Hmm... So you made me to do some "real" work here, and guess what?:
> there is one serious checkpatch warning! ;-) Plus, this new parameter
> should be added to the function description. Otherwise:
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
>
> Thanks,
> Jarek P.
>
> PS: I guess full "Don't" would show we really mean it...
Okay :) Here is the last round, before the night !
Thanks again
[RFC] pkt_sched: gen_estimator: Don't report fake rate estimators
We currently send TCA_STATS_RATE_EST elements to netlink users, even if no estimator
is running.
# tc -s -d qdisc
qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 112833764978 bytes 1495081739 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
User has no way to tell if the "rate 0bit 0pps" is a real estimation, or a fake
one (because no estimator is active)
After this patch, tc command output is :
$ tc -s -d qdisc
qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 561075 bytes 1196 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
We add a parameter to gnet_stats_copy_rate_est() function so that
it can use gen_estimator_active(bstats, r), as suggested by Jarek.
This parameter can be NULL if check is not necessary, (htb for
example has a mandatory rate estimator)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-10-02 14:32:18 +04:00
gnet_stats_copy_rate_est ( struct gnet_dump * d ,
const struct gnet_stats_basic_packed * b ,
2013-06-06 19:43:22 +04:00
struct gnet_stats_rate_est64 * r )
2005-04-17 02:20:36 +04:00
{
2013-06-06 19:43:22 +04:00
struct gnet_stats_rate_est est ;
int res ;
pkt_sched: gen_estimator: Dont report fake rate estimators
Jarek Poplawski a écrit :
>
>
> Hmm... So you made me to do some "real" work here, and guess what?:
> there is one serious checkpatch warning! ;-) Plus, this new parameter
> should be added to the function description. Otherwise:
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
>
> Thanks,
> Jarek P.
>
> PS: I guess full "Don't" would show we really mean it...
Okay :) Here is the last round, before the night !
Thanks again
[RFC] pkt_sched: gen_estimator: Don't report fake rate estimators
We currently send TCA_STATS_RATE_EST elements to netlink users, even if no estimator
is running.
# tc -s -d qdisc
qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 112833764978 bytes 1495081739 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
User has no way to tell if the "rate 0bit 0pps" is a real estimation, or a fake
one (because no estimator is active)
After this patch, tc command output is :
$ tc -s -d qdisc
qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 561075 bytes 1196 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
We add a parameter to gnet_stats_copy_rate_est() function so that
it can use gen_estimator_active(bstats, r), as suggested by Jarek.
This parameter can be NULL if check is not necessary, (htb for
example has a mandatory rate estimator)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-10-02 14:32:18 +04:00
if ( b & & ! gen_estimator_active ( b , r ) )
return 0 ;
2013-06-06 19:43:22 +04:00
est . bps = min_t ( u64 , UINT_MAX , r - > bps ) ;
/* we have some time before reaching 2^32 packets per second */
est . pps = r - > pps ;
2005-04-17 02:20:36 +04:00
if ( d - > compat_tc_stats ) {
2013-06-06 19:43:22 +04:00
d - > tc_stats . bps = est . bps ;
d - > tc_stats . pps = est . pps ;
2005-04-17 02:20:36 +04:00
}
2013-06-06 19:43:22 +04:00
if ( d - > tail ) {
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 ) ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-07-10 01:22:04 +04:00
EXPORT_SYMBOL ( gnet_stats_copy_rate_est ) ;
2005-04-17 02:20:36 +04:00
2014-09-28 22:54:24 +04:00
static void
__gnet_stats_copy_queue_cpu ( struct gnet_stats_queue * qstats ,
const struct gnet_stats_queue __percpu * q )
{
int i ;
for_each_possible_cpu ( i ) {
const struct gnet_stats_queue * qcpu = per_cpu_ptr ( q , i ) ;
qstats - > qlen = 0 ;
qstats - > backlog + = qcpu - > backlog ;
qstats - > drops + = qcpu - > drops ;
qstats - > requeues + = qcpu - > requeues ;
qstats - > overlimits + = qcpu - > overlimits ;
}
}
static void __gnet_stats_copy_queue ( struct gnet_stats_queue * qstats ,
const struct gnet_stats_queue __percpu * cpu ,
const struct gnet_stats_queue * q ,
__u32 qlen )
{
if ( cpu ) {
__gnet_stats_copy_queue_cpu ( qstats , cpu ) ;
} else {
qstats - > qlen = q - > qlen ;
qstats - > backlog = q - > backlog ;
qstats - > drops = q - > drops ;
qstats - > requeues = q - > requeues ;
qstats - > overlimits = q - > overlimits ;
}
qstats - > qlen = qlen ;
}
2005-04-17 02:20:36 +04:00
/**
* gnet_stats_copy_queue - copy queue statistics into statistics TLV
* @ d : dumping handle
2014-09-28 22:54:24 +04:00
* @ cpu_q : per cpu queue statistics
2005-04-17 02:20:36 +04:00
* @ q : queue statistics
2014-09-28 22:53:57 +04:00
* @ qlen : queue length statistics
2005-04-17 02:20:36 +04:00
*
* Appends the queue statistics to the top level TLV created by
2014-09-28 22:54:24 +04:00
* gnet_stats_start_copy ( ) . Using per cpu queue statistics if
* they are available .
2005-04-17 02:20:36 +04:00
*
* Returns 0 on success or - 1 with the statistic lock released
* if the room in the socket buffer was not sufficient .
*/
int
2014-09-28 22:53:57 +04:00
gnet_stats_copy_queue ( struct gnet_dump * d ,
2014-09-28 22:54:24 +04:00
struct gnet_stats_queue __percpu * cpu_q ,
2014-09-28 22:53:57 +04:00
struct gnet_stats_queue * q , __u32 qlen )
2005-04-17 02:20:36 +04:00
{
2014-09-28 22:54:24 +04:00
struct gnet_stats_queue qstats = { 0 } ;
__gnet_stats_copy_queue ( & qstats , cpu_q , q , qlen ) ;
2014-09-28 22:53:57 +04:00
2005-04-17 02:20:36 +04:00
if ( d - > compat_tc_stats ) {
2014-09-28 22:54:24 +04:00
d - > tc_stats . drops = qstats . drops ;
d - > tc_stats . qlen = qstats . qlen ;
d - > tc_stats . backlog = qstats . backlog ;
d - > tc_stats . overlimits = qstats . overlimits ;
2005-04-17 02:20:36 +04:00
}
if ( d - > tail )
2014-09-28 22:54:24 +04:00
return gnet_stats_copy ( d , TCA_STATS_QUEUE ,
& qstats , sizeof ( qstats ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-07-10 01:22:04 +04:00
EXPORT_SYMBOL ( gnet_stats_copy_queue ) ;
2005-04-17 02:20:36 +04:00
/**
* gnet_stats_copy_app - copy application specific statistics into statistics TLV
* @ d : dumping handle
* @ st : application specific statistics data
* @ len : length of data
*
2014-09-04 18:44:36 +04:00
* Appends the application specific statistics to the top level TLV created by
2005-04-17 02:20:36 +04:00
* gnet_stats_start_copy ( ) and remembers the data for XSTATS if the dumping
* handle is in backward compatibility mode .
*
* Returns 0 on success or - 1 with the statistic lock released
* if the room in the socket buffer was not sufficient .
*/
int
gnet_stats_copy_app ( struct gnet_dump * d , void * st , int len )
{
if ( d - > compat_xstats ) {
2015-02-14 01:47:05 +03:00
d - > xstats = kmemdup ( st , len , GFP_ATOMIC ) ;
if ( ! d - > xstats )
goto err_out ;
2005-04-17 02:20:36 +04:00
d - > xstats_len = len ;
}
if ( d - > tail )
return gnet_stats_copy ( d , TCA_STATS_APP , st , len ) ;
return 0 ;
2015-02-14 01:47:05 +03:00
err_out :
d - > xstats_len = 0 ;
spin_unlock_bh ( d - > lock ) ;
return - 1 ;
2005-04-17 02:20:36 +04:00
}
2010-07-10 01:22:04 +04:00
EXPORT_SYMBOL ( gnet_stats_copy_app ) ;
2005-04-17 02:20:36 +04:00
/**
* gnet_stats_finish_copy - finish dumping procedure
* @ d : dumping handle
*
* Corrects the length of the top level TLV to include all TLVs added
* by gnet_stats_copy_XXX ( ) calls . Adds the backward compatibility TLVs
* if gnet_stats_start_copy_compat ( ) was used and releases the statistics
* lock .
*
* Returns 0 on success or - 1 with the statistic lock released
* if the room in the socket buffer was not sufficient .
*/
int
gnet_stats_finish_copy ( struct gnet_dump * d )
{
if ( d - > tail )
2008-01-23 09:11:17 +03:00
d - > tail - > nla_len = skb_tail_pointer ( d - > skb ) - ( u8 * ) d - > tail ;
2005-04-17 02:20:36 +04:00
if ( d - > compat_tc_stats )
if ( gnet_stats_copy ( d , d - > compat_tc_stats , & d - > tc_stats ,
sizeof ( d - > tc_stats ) ) < 0 )
return - 1 ;
if ( d - > compat_xstats & & d - > xstats ) {
if ( gnet_stats_copy ( d , d - > compat_xstats , d - > xstats ,
d - > xstats_len ) < 0 )
return - 1 ;
}
2015-02-14 01:47:05 +03:00
kfree ( d - > xstats ) ;
d - > xstats = NULL ;
d - > xstats_len = 0 ;
2005-04-17 02:20:36 +04:00
spin_unlock_bh ( d - > lock ) ;
return 0 ;
}
EXPORT_SYMBOL ( gnet_stats_finish_copy ) ;