/*1* net/core/gen_stats.c2*3* This program is free software; you can redistribute it and/or4* modify it under the terms of the GNU General Public License5* as published by the Free Software Foundation; either version6* 2 of the License, or (at your option) any later version.7*8* Authors: Thomas Graf <[email protected]>9* Jamal Hadi Salim10* Alexey Kuznetsov, <[email protected]>11*12* See Documentation/networking/gen_stats.txt13*/1415#include <linux/types.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/interrupt.h>19#include <linux/socket.h>20#include <linux/rtnetlink.h>21#include <linux/gen_stats.h>22#include <net/netlink.h>23#include <net/gen_stats.h>242526static inline int27gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)28{29NLA_PUT(d->skb, type, size, buf);30return 0;3132nla_put_failure:33spin_unlock_bh(d->lock);34return -1;35}3637/**38* gnet_stats_start_copy_compat - start dumping procedure in compatibility mode39* @skb: socket buffer to put statistics TLVs into40* @type: TLV type for top level statistic TLV41* @tc_stats_type: TLV type for backward compatibility struct tc_stats TLV42* @xstats_type: TLV type for backward compatibility xstats TLV43* @lock: statistics lock44* @d: dumping handle45*46* Initializes the dumping handle, grabs the statistic lock and appends47* an empty TLV header to the socket buffer for use a container for all48* other statistic TLVS.49*50* The dumping handle is marked to be in backward compatibility mode telling51* all gnet_stats_copy_XXX() functions to fill a local copy of struct tc_stats.52*53* Returns 0 on success or -1 if the room in the socket buffer was not sufficient.54*/55int56gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,57int xstats_type, spinlock_t *lock, struct gnet_dump *d)58__acquires(lock)59{60memset(d, 0, sizeof(*d));6162spin_lock_bh(lock);63d->lock = lock;64if (type)65d->tail = (struct nlattr *)skb_tail_pointer(skb);66d->skb = skb;67d->compat_tc_stats = tc_stats_type;68d->compat_xstats = xstats_type;6970if (d->tail)71return gnet_stats_copy(d, type, NULL, 0);7273return 0;74}75EXPORT_SYMBOL(gnet_stats_start_copy_compat);7677/**78* gnet_stats_start_copy_compat - start dumping procedure in compatibility mode79* @skb: socket buffer to put statistics TLVs into80* @type: TLV type for top level statistic TLV81* @lock: statistics lock82* @d: dumping handle83*84* Initializes the dumping handle, grabs the statistic lock and appends85* an empty TLV header to the socket buffer for use a container for all86* other statistic TLVS.87*88* Returns 0 on success or -1 if the room in the socket buffer was not sufficient.89*/90int91gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,92struct gnet_dump *d)93{94return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);95}96EXPORT_SYMBOL(gnet_stats_start_copy);9798/**99* gnet_stats_copy_basic - copy basic statistics into statistic TLV100* @d: dumping handle101* @b: basic statistics102*103* Appends the basic statistics to the top level TLV created by104* gnet_stats_start_copy().105*106* Returns 0 on success or -1 with the statistic lock released107* if the room in the socket buffer was not sufficient.108*/109int110gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b)111{112if (d->compat_tc_stats) {113d->tc_stats.bytes = b->bytes;114d->tc_stats.packets = b->packets;115}116117if (d->tail) {118struct gnet_stats_basic sb;119120memset(&sb, 0, sizeof(sb));121sb.bytes = b->bytes;122sb.packets = b->packets;123return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb));124}125return 0;126}127EXPORT_SYMBOL(gnet_stats_copy_basic);128129/**130* gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV131* @d: dumping handle132* @b: basic statistics133* @r: rate estimator statistics134*135* Appends the rate estimator statistics to the top level TLV created by136* gnet_stats_start_copy().137*138* Returns 0 on success or -1 with the statistic lock released139* if the room in the socket buffer was not sufficient.140*/141int142gnet_stats_copy_rate_est(struct gnet_dump *d,143const struct gnet_stats_basic_packed *b,144struct gnet_stats_rate_est *r)145{146if (b && !gen_estimator_active(b, r))147return 0;148149if (d->compat_tc_stats) {150d->tc_stats.bps = r->bps;151d->tc_stats.pps = r->pps;152}153154if (d->tail)155return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r));156157return 0;158}159EXPORT_SYMBOL(gnet_stats_copy_rate_est);160161/**162* gnet_stats_copy_queue - copy queue statistics into statistics TLV163* @d: dumping handle164* @q: queue statistics165*166* Appends the queue statistics to the top level TLV created by167* gnet_stats_start_copy().168*169* Returns 0 on success or -1 with the statistic lock released170* if the room in the socket buffer was not sufficient.171*/172int173gnet_stats_copy_queue(struct gnet_dump *d, struct gnet_stats_queue *q)174{175if (d->compat_tc_stats) {176d->tc_stats.drops = q->drops;177d->tc_stats.qlen = q->qlen;178d->tc_stats.backlog = q->backlog;179d->tc_stats.overlimits = q->overlimits;180}181182if (d->tail)183return gnet_stats_copy(d, TCA_STATS_QUEUE, q, sizeof(*q));184185return 0;186}187EXPORT_SYMBOL(gnet_stats_copy_queue);188189/**190* gnet_stats_copy_app - copy application specific statistics into statistics TLV191* @d: dumping handle192* @st: application specific statistics data193* @len: length of data194*195* Appends the application sepecific statistics to the top level TLV created by196* gnet_stats_start_copy() and remembers the data for XSTATS if the dumping197* handle is in backward compatibility mode.198*199* Returns 0 on success or -1 with the statistic lock released200* if the room in the socket buffer was not sufficient.201*/202int203gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)204{205if (d->compat_xstats) {206d->xstats = st;207d->xstats_len = len;208}209210if (d->tail)211return gnet_stats_copy(d, TCA_STATS_APP, st, len);212213return 0;214}215EXPORT_SYMBOL(gnet_stats_copy_app);216217/**218* gnet_stats_finish_copy - finish dumping procedure219* @d: dumping handle220*221* Corrects the length of the top level TLV to include all TLVs added222* by gnet_stats_copy_XXX() calls. Adds the backward compatibility TLVs223* if gnet_stats_start_copy_compat() was used and releases the statistics224* lock.225*226* Returns 0 on success or -1 with the statistic lock released227* if the room in the socket buffer was not sufficient.228*/229int230gnet_stats_finish_copy(struct gnet_dump *d)231{232if (d->tail)233d->tail->nla_len = skb_tail_pointer(d->skb) - (u8 *)d->tail;234235if (d->compat_tc_stats)236if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,237sizeof(d->tc_stats)) < 0)238return -1;239240if (d->compat_xstats && d->xstats) {241if (gnet_stats_copy(d, d->compat_xstats, d->xstats,242d->xstats_len) < 0)243return -1;244}245246spin_unlock_bh(d->lock);247return 0;248}249EXPORT_SYMBOL(gnet_stats_finish_copy);250251252