Annotation of embedaddon/bmon/src/item.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * item.c              Item Management
        !             3:  *
        !             4:  * Copyright (c) 2001-2004 Thomas Graf <tgraf@suug.ch>
        !             5:  *
        !             6:  * Permission is hereby granted, free of charge, to any person obtaining a
        !             7:  * copy of this software and associated documentation files (the "Software"),
        !             8:  * to deal in the Software without restriction, including without limitation
        !             9:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
        !            10:  * and/or sell copies of the Software, and to permit persons to whom the
        !            11:  * Software is furnished to do so, subject to the following conditions:
        !            12:  *
        !            13:  * The above copyright notice and this permission notice shall be included
        !            14:  * in all copies or substantial portions of the Software.
        !            15:  *
        !            16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
        !            17:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
        !            19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
        !            21:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
        !            22:  * DEALINGS IN THE SOFTWARE.
        !            23:  */
        !            24: 
        !            25: #include <bmon/bmon.h>
        !            26: #include <bmon/node.h>
        !            27: #include <bmon/conf.h>
        !            28: #include <bmon/item.h>
        !            29: #include <bmon/itemtab.h>
        !            30: #include <bmon/input.h>
        !            31: #include <bmon/graph.h>
        !            32: #include <bmon/utils.h>
        !            33: 
        !            34: #define MAX_POLICY             255
        !            35: #define SECOND                 1.0f
        !            36: #define MINUTE                60.0f
        !            37: #define HOUR                3600.0f
        !            38: #define DAY                86400.0f
        !            39: 
        !            40: static char * allowed_items[MAX_POLICY];
        !            41: static char * denied_items[MAX_POLICY];
        !            42: static char * allowed_attrs[MAX_POLICY];
        !            43: static char * denied_attrs[MAX_POLICY];
        !            44: static int allow_all_attrs;
        !            45: 
        !            46: static inline uint8_t attr_hash(int type)
        !            47: {
        !            48:        return (type & 0xFF) % ATTR_HASH_MAX;
        !            49: }
        !            50: 
        !            51: stat_attr_t *lookup_attr(item_t *it, int type)
        !            52: {
        !            53:        stat_attr_t *a;
        !            54:        uint8_t h = attr_hash(type);
        !            55:        
        !            56:        for (a = it->i_attrs[h]; a; a = a->a_next)
        !            57:                if (a->a_type == type)
        !            58:                        return a;
        !            59:        return NULL;
        !            60: }
        !            61: 
        !            62: b_cnt_t attr_get_rx(stat_attr_t *a)
        !            63: {
        !            64: #ifndef DISABLE_OVERFLOW_WORKAROUND
        !            65:        return (a->a_rx.r_overflows * OVERFLOW_LIMIT) + a->a_rx.r_total;
        !            66: #else
        !            67:        return a->a_rx.r_total;
        !            68: #endif
        !            69: }
        !            70: 
        !            71: rate_cnt_t attr_get_rx_rate(stat_attr_t *a)
        !            72: {
        !            73:        return a->a_rx.r_tps;
        !            74: }
        !            75: 
        !            76: b_cnt_t attr_get_tx(stat_attr_t *a)
        !            77: {
        !            78: #ifndef DISABLE_OVERFLOW_WORKAROUND
        !            79:        return (a->a_tx.r_overflows * OVERFLOW_LIMIT) + a->a_tx.r_total;
        !            80: #else
        !            81:        return a->a_tx.r_total;
        !            82: #endif
        !            83: }
        !            84: 
        !            85: rate_cnt_t attr_get_tx_rate(stat_attr_t *a)
        !            86: {
        !            87:        return a->a_tx.r_tps;
        !            88: }
        !            89: void foreach_attr(item_t *i, void (*cb)(stat_attr_t *, void *), void *arg)
        !            90: {
        !            91:        int m;
        !            92: 
        !            93:        for (m = 0; m < ATTR_HASH_MAX; m++) {
        !            94:                stat_attr_t *a;
        !            95:                for (a = i->i_attrs[m]; a; a = a->a_next)
        !            96:                        cb(a, arg);
        !            97:        }
        !            98: }
        !            99: 
        !           100: static struct attr_type attr_types[] = {
        !           101: #define IGNORE_OVERFLOWS 1
        !           102: #define IS_RATE 2
        !           103: #define __A(_I, _N, _D, _U, _F) { .id = _I, .name = _N, .desc = _D, .flags = _F, .unit = _U }
        !           104:        __A(BYTES, "bytes", "Bytes", U_BYTES, 0),
        !           105:        __A(PACKETS, "packets", "Packets", U_NUMBER, 0),
        !           106:        __A(ERRORS, "errors", "Errors", U_NUMBER, 0),
        !           107:        __A(DROP, "drop", "Dropped", U_NUMBER, 0),
        !           108:        __A(FIFO, "fifo", "FIFO Err", U_NUMBER, 0),
        !           109:        __A(FRAME, "frame", "Frame Err", U_NUMBER, 0),
        !           110:        __A(COMPRESSED, "compressed", "Compressed", U_NUMBER, 0),
        !           111:        __A(MULTICAST, "multicast", "Multicast", U_NUMBER, 0),
        !           112:        __A(BROADCAST, "broadcast", "Broadcast", U_NUMBER, 0),
        !           113:        __A(LENGTH_ERRORS, "len_err", "Length Err", U_NUMBER, 0),
        !           114:        __A(OVER_ERRORS, "over_err", "Over Err", U_NUMBER, 0),
        !           115:        __A(CRC_ERRORS, "crc_err", "CRC Err", U_NUMBER, 0),
        !           116:        __A(MISSED_ERRORS, "miss_err", "Missed Err", U_NUMBER, 0),
        !           117:        __A(ABORTED_ERRORS, "abort_err", "Aborted Err", U_NUMBER, 0),
        !           118:        __A(CARRIER_ERRORS, "carrier_err", "Carrier Err", U_NUMBER, 0),
        !           119:        __A(HEARTBEAT_ERRORS, "hbeat_err", "HBeat Err", U_NUMBER, 0),
        !           120:        __A(WINDOW_ERRORS, "win_err", "Window Err", U_NUMBER, 0),
        !           121:        __A(COLLISIONS, "collisions", "Collisions", U_NUMBER, 0),
        !           122:        __A(OVERLIMITS, "overlimits", "Overlimits", U_NUMBER, 0),
        !           123:        __A(BPS, "bps", "Bits/s", U_BYTES, IGNORE_OVERFLOWS | IS_RATE),
        !           124:        __A(PPS, "pps", "Packets/s", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
        !           125:        __A(QLEN, "qlen", "Queue Len", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
        !           126:        __A(BACKLOG, "backlog", "Backlog", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
        !           127:        __A(REQUEUES, "requeues", "Requeues", U_NUMBER, 0)
        !           128: #undef __A
        !           129: };
        !           130: 
        !           131: int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg)
        !           132: {
        !           133:        int i, ret;
        !           134: 
        !           135:        for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++) {
        !           136:                ret = cb(&attr_types[i], arg);
        !           137:                if (ret < 0)
        !           138:                        return ret;
        !           139:        }
        !           140: 
        !           141:        return 0;
        !           142: }
        !           143: 
        !           144: const char * type2name(int type)
        !           145: {
        !           146:        int i;
        !           147: 
        !           148:        for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
        !           149:                if (attr_types[i].id == type)
        !           150:                        return attr_types[i].name;
        !           151: 
        !           152:        return NULL;
        !           153: }
        !           154: 
        !           155: int name2type(const char *name)
        !           156: {
        !           157:        int i;
        !           158: 
        !           159:        for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
        !           160:                if (!strcasecmp(attr_types[i].name, name))
        !           161:                        return attr_types[i].id;
        !           162: 
        !           163:        return INT_MAX;
        !           164: }
        !           165: 
        !           166: const char * type2desc(int type)
        !           167: {
        !           168:        int i;
        !           169:        static char str[256];
        !           170: 
        !           171:        for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
        !           172:                if (attr_types[i].id == type)
        !           173:                        return attr_types[i].desc;
        !           174: 
        !           175:        snprintf(str, sizeof(str), "unknown (%d)", type);
        !           176:        return str;
        !           177: }
        !           178: 
        !           179: int attr_ignore_overflows(int type)
        !           180: {
        !           181:        int i;
        !           182: 
        !           183:        for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
        !           184:                if (attr_types[i].id == type &&
        !           185:                    attr_types[i].flags & IGNORE_OVERFLOWS)
        !           186:                        return 1;
        !           187: 
        !           188:        return 0;
        !           189: }
        !           190: 
        !           191: int attr_is_rate(int type)
        !           192: {
        !           193:        int i;
        !           194: 
        !           195:        for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
        !           196:                if (attr_types[i].id == type &&
        !           197:                    attr_types[i].flags & IS_RATE)
        !           198:                        return 1;
        !           199: 
        !           200:        return 0;
        !           201: }
        !           202: 
        !           203: int attr_unit(int type)
        !           204: {
        !           205:        int i;
        !           206: 
        !           207:        for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
        !           208:                if (attr_types[i].id == type)
        !           209:                        return attr_types[i].unit;
        !           210: 
        !           211:        return 0;
        !           212: }
        !           213: 
        !           214: static int match_mask(const char *mask, const char *str)
        !           215: {
        !           216:        int i, n;
        !           217:        char c;
        !           218: 
        !           219:        if (!mask || !str)
        !           220:                return 0;
        !           221:        
        !           222:        for (i = 0, n = 0; mask[i] != '\0'; i++, n++) {
        !           223:                if (mask[i] == '*') {
        !           224:                        c = tolower(mask[i+1]);
        !           225:                        
        !           226:                        if (c == '\0')
        !           227:                                return 1; /* nothing after wildcard, matches in any case */
        !           228:                        
        !           229:                        /*look for c in str, c is the character after the wildcard */
        !           230:                        for (; tolower(str[n]) != c; n++)
        !           231:                                if (str[n] == '\0')
        !           232:                                        return 0; /* character after wildcard was not found */
        !           233:                        
        !           234:                        n--;
        !           235:                } else if (tolower(mask[i]) != tolower(str[n]))
        !           236:                        return 0;
        !           237:        }
        !           238: 
        !           239:        return str[n] == '\0' ? 1 : 0;
        !           240: }
        !           241: 
        !           242: static int item_allowed(const char *name)
        !           243: {
        !           244:        int n;
        !           245:        
        !           246:        if (!allowed_items[0] && !denied_items[0])
        !           247:                return 1;
        !           248: 
        !           249:        if (!allowed_items[0]) {
        !           250:                for (n = 0; n < MAX_POLICY && denied_items[n]; n++)
        !           251:                        if (match_mask(denied_items[n], name))
        !           252:                                return 0;
        !           253:        
        !           254:                return 1;
        !           255:        }
        !           256: 
        !           257:        for (n = 0; n < MAX_POLICY && denied_items[n]; n++)
        !           258:                if (match_mask(denied_items[n], name))
        !           259:                        return 0;
        !           260:        
        !           261:        for (n=0; n < MAX_POLICY && allowed_items[n]; n++)
        !           262:                if (match_mask(allowed_items[n], name))
        !           263:                        return 1;
        !           264: 
        !           265:        return 0;
        !           266: }
        !           267: 
        !           268: void item_parse_policy(const char *policy)
        !           269: {
        !           270:        static int set = 0;
        !           271:        int i, a = 0, d = 0, f = 0;
        !           272:        char *p, *s;
        !           273: 
        !           274:        if (set)
        !           275:                return;
        !           276:        set = 1;
        !           277:        
        !           278:        s = strdup(policy);
        !           279:        
        !           280:        for (i = 0, p = s; ; i++) {
        !           281:                if (s[i] == ',' || s[i] == '\0') {
        !           282: 
        !           283:                        f = s[i] == '\0' ? 1 : 0;
        !           284:                        s[i] = '\0';
        !           285:                        
        !           286:                        if ('!' == *p) {
        !           287:                                if (d > (MAX_POLICY - 1))
        !           288:                                        break;
        !           289:                                denied_items[d++] = strdup(++p);
        !           290:                        } else {
        !           291:                                if(a > (MAX_POLICY - 1))
        !           292:                                        break;
        !           293:                                allowed_items[a++] = strdup(p);
        !           294:                        }
        !           295:                        
        !           296:                        if (f)
        !           297:                                break;
        !           298:                        
        !           299:                        p = &s[i+1];
        !           300:                }
        !           301:        }
        !           302:        
        !           303:        xfree(s);
        !           304: }
        !           305: 
        !           306: static inline int collect_history(int type)
        !           307: {
        !           308:        int n;
        !           309:        const char *name = type2name(type);
        !           310: 
        !           311:        if (allow_all_attrs)
        !           312:                return 1;
        !           313: 
        !           314:        if (!allowed_attrs[0] && !denied_attrs[0]) {
        !           315:                if (!strcmp(name, "bytes") || !strcmp(name, "packets"))
        !           316:                        return 1;
        !           317:                else
        !           318:                        return 0;
        !           319:        }
        !           320: 
        !           321:        if (!allowed_attrs[0]) {
        !           322:                for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
        !           323:                        if (!strcasecmp(denied_attrs[n], name))
        !           324:                                return 0;
        !           325:                return 1;
        !           326:        }
        !           327: 
        !           328:        for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
        !           329:                if (!strcasecmp(denied_attrs[n], name))
        !           330:                        return 0;
        !           331:        
        !           332:        for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++)
        !           333:                if (!strcasecmp(allowed_attrs[n], name))
        !           334:                        return 1;
        !           335: 
        !           336:        return 0;
        !           337: }
        !           338: 
        !           339: void parse_attr_policy(const char *policy)
        !           340: {
        !           341:        static int set = 0;
        !           342:        int i, a = 0, d = 0, f = 0;
        !           343:        char *p, *s;
        !           344: 
        !           345:        if (set)
        !           346:                return;
        !           347:        set = 1;
        !           348: 
        !           349:        if (!strcasecmp(policy, "all")) {
        !           350:                allow_all_attrs = 1;
        !           351:                return ;
        !           352:        }
        !           353: 
        !           354:        s = strdup(policy);
        !           355:        
        !           356:        for (i = 0, p = s; ; i++) {
        !           357:                if (s[i] == ',' || s[i] == '\0') {
        !           358: 
        !           359:                        f = s[i] == '\0' ? 1 : 0;
        !           360:                        s[i] = '\0';
        !           361:                        
        !           362:                        if ('!' == *p) {
        !           363:                                if (d > (MAX_POLICY - 1))
        !           364:                                        break;
        !           365:                                denied_attrs[d++] = strdup(++p);
        !           366:                        } else {
        !           367:                                if(a > (MAX_POLICY - 1))
        !           368:                                        break;
        !           369:                                allowed_attrs[a++] = strdup(p);
        !           370:                        }
        !           371:                        
        !           372:                        if (f)
        !           373:                                break;
        !           374:                        
        !           375:                        p = &s[i+1];
        !           376:                }
        !           377:        }
        !           378:        
        !           379:        xfree(s);
        !           380: }
        !           381: 
        !           382: item_t * lookup_item(node_t *node, const char *name, uint32_t handle,
        !           383:                     item_t *parent)
        !           384: {
        !           385:        int i;
        !           386:        
        !           387:        if (NULL == node)
        !           388:                BUG();
        !           389:        
        !           390:        if (NULL == node->n_items) {
        !           391:                node->n_nitems = 32;
        !           392:                node->n_items = xcalloc(node->n_nitems, sizeof(item_t));
        !           393:        }
        !           394:        
        !           395:        for (i = 0; i < node->n_nitems; i++)
        !           396:                if (!strcmp(name, node->n_items[i].i_name) &&
        !           397:                        node->n_items[i].i_handle == handle &&
        !           398:                        node->n_items[i].i_parent == (parent ? parent->i_index : 0))
        !           399:                        return !(node->n_items[i].i_flags & ITEM_FLAG_UPDATED) ?
        !           400:                                &node->n_items[i] : NULL;
        !           401:        
        !           402:        if (!handle && !item_allowed(name))
        !           403:                return NULL;
        !           404:        
        !           405:        for (i = 0; i < node->n_nitems; i++)
        !           406:                if (node->n_items[i].i_name[0] == '\0')
        !           407:                        break;
        !           408:        
        !           409:        if (i >= node->n_nitems) {
        !           410:                int oldsize = node->n_nitems;
        !           411:                node->n_nitems += 32;
        !           412:                node->n_items = xrealloc(node->n_items, node->n_nitems * sizeof(item_t));
        !           413:                memset(node->n_items + oldsize, 0, (node->n_nitems - oldsize) * sizeof(item_t));
        !           414:        }
        !           415:        
        !           416:        memset(&node->n_items[i], 0, sizeof(node->n_items[i]));
        !           417:        strncpy(node->n_items[i].i_name, name, sizeof(node->n_items[i].i_name) - 1);
        !           418:        node->n_items[i].i_handle = handle;
        !           419:        node->n_items[i].i_parent = parent ? parent->i_index : 0;
        !           420:        node->n_items[i].i_index = i;
        !           421:        node->n_items[i].i_node = node;
        !           422:        node->n_items[i].i_lifetime = get_lifetime();
        !           423: 
        !           424:        if (!node->n_from)
        !           425:                node->n_items[i].i_flags |= ITEM_FLAG_LOCAL;
        !           426: 
        !           427:        {
        !           428:                struct it_item *tab = lookup_tab(&node->n_items[i]);
        !           429: 
        !           430:                if (tab && tab->ii_desc)
        !           431:                        node->n_items[i].i_desc = tab->ii_desc;
        !           432:        }
        !           433: 
        !           434:        if (parent)
        !           435:                parent->i_flags |= ITEM_FLAG_HAS_CHILDS;
        !           436: 
        !           437:        return &node->n_items[i];
        !           438: }
        !           439: 
        !           440: void foreach_child(node_t *node, item_t *parent, void (*cb)(item_t *, void *),
        !           441:                   void *arg)
        !           442: {
        !           443:        int i;
        !           444: 
        !           445:        for (i = 0; i < node->n_nitems; i++)
        !           446:                if (node->n_items[i].i_parent == parent->i_index &&
        !           447:                    node->n_items[i].i_flags & ITEM_FLAG_IS_CHILD)
        !           448:                        cb(&node->n_items[i], arg);
        !           449: }
        !           450: 
        !           451: void reset_item(item_t *i)
        !           452: {
        !           453:        i->i_flags &= ~ITEM_FLAG_UPDATED;
        !           454: }
        !           455: 
        !           456: void remove_unused_items(item_t *i)
        !           457: {
        !           458:        if (--(i->i_lifetime) <= 0) {
        !           459:                int m;
        !           460:                for (m = 0; m < ATTR_HASH_MAX; m++) {
        !           461:                        stat_attr_t *a, *next;
        !           462:                        for (a = i->i_attrs[m]; a; a = next) {
        !           463:                                next = a->a_next;
        !           464:                                free(a);
        !           465:                        }
        !           466:                }
        !           467:                if (!(i->i_flags & ITEM_FLAG_LOCAL)) {
        !           468:                        if (i->i_desc)
        !           469:                                free(i->i_desc);
        !           470:                }
        !           471:                memset(i, 0, sizeof(item_t));
        !           472:        }
        !           473: }
        !           474: 
        !           475: static void calc_rate(rate_t *rate, timestamp_t *ts, int ignore_overflows)
        !           476: {
        !           477:        float diff;
        !           478: 
        !           479:        if (!rate->r_prev_total) {
        !           480:                rate->r_prev_total = rate->r_total;
        !           481:                COPY_TS(&rate->r_last_update, ts);
        !           482:                return;
        !           483:        }
        !           484:        
        !           485:        diff = time_diff(&rate->r_last_update, ts);
        !           486:        
        !           487:        if (diff >= get_rate_interval()) {
        !           488:                if (rate->r_total) {
        !           489:                        rate_cnt_t old_rate;
        !           490: 
        !           491:                        b_cnt_t t = (rate->r_total - rate->r_prev_total);
        !           492:                        old_rate = rate->r_tps;
        !           493: 
        !           494: #ifndef DISABLE_OVERFLOW_WORKAROUND
        !           495:                        /* HACK:
        !           496:                         *
        !           497:                         * Workaround for counter overflow, all input methods
        !           498:                         * except kstat in 64bit mode use a 32bit counter which
        !           499:                         * tends to overflow. We can work around the problem
        !           500:                         * when assuming that there will be no  scenario with
        !           501:                         * 4GiB/s and no more than 1 overflow per second.
        !           502:                         */
        !           503:                        if (t >= OVERFLOW_LIMIT &&
        !           504:                            !rate->r_is64bit &&
        !           505:                            !ignore_overflows) {
        !           506:                                rate->r_tps = OVERFLOW_LIMIT -
        !           507:                                        (rate->r_prev_total - rate->r_total);
        !           508:                                rate->r_overflows++;
        !           509:                        } else
        !           510: #endif
        !           511:                                rate->r_tps  = (rate_cnt_t) t;
        !           512: 
        !           513:                        rate->r_tps /= diff;
        !           514:                        rate->r_tps = ((rate->r_tps * 3) + old_rate) / 4;
        !           515:                        rate->r_prev_total = rate->r_total;
        !           516:                }
        !           517: 
        !           518:                COPY_TS(&rate->r_last_update, ts);
        !           519:        }
        !           520: }
        !           521: 
        !           522: static inline b_cnt_t get_real_total(rate_t *r, unsigned int prev_overflows,
        !           523:                                     b_cnt_t prev_total)
        !           524: {
        !           525:        b_cnt_t res;
        !           526:        unsigned int new_overflows = (r->r_overflows - prev_overflows);
        !           527: 
        !           528: #ifndef DISABLE_OVERFLOW_WORKAROUND
        !           529:        if (new_overflows)
        !           530:                res = (new_overflows * OVERFLOW_LIMIT) + r->r_total - prev_total;
        !           531:        else
        !           532: #endif
        !           533:                res = r->r_total - prev_total;
        !           534: 
        !           535:        return res;
        !           536: }
        !           537: 
        !           538: static inline void update_history_data(hist_data_t *hd, rate_t *r,
        !           539:                                       int index, double diff)
        !           540: {
        !           541:        double t;
        !           542:        
        !           543:        t = (double) get_real_total(r, hd->hd_overflows,
        !           544:            hd->hd_prev_total) / diff;
        !           545:        hd->hd_data[index] = (rate_cnt_t) t;
        !           546:        hd->hd_prev_total = r->r_total;
        !           547:        hd->hd_overflows = r->r_overflows;
        !           548: }
        !           549: 
        !           550: static void update_history_element(hist_elem_t *he, rate_t *rx, rate_t *tx,
        !           551:                                   timestamp_t *ts, float unit)
        !           552: {
        !           553:        double diff = time_diff(&he->he_last_update, ts);
        !           554:        
        !           555:        if (!he->he_last_update.tv_sec)
        !           556:                diff = 0.0f;
        !           557: 
        !           558:        /* Do not updated histor for graphs with intervals
        !           559:         * less than the reading interval. */
        !           560:        if (get_read_interval() > unit)
        !           561:                goto discard;
        !           562: 
        !           563:        /* Discard outdated updates */
        !           564:        if (diff >= (unit + (get_hb_factor() * unit)))
        !           565:                goto discard;
        !           566: 
        !           567:        if (!he->he_last_update.tv_sec) {
        !           568:                he->he_rx.hd_prev_total = rx->r_total;
        !           569:                he->he_tx.hd_prev_total = tx->r_total;
        !           570:        } else if (get_read_interval() == unit) {
        !           571:                update_history_data(&he->he_rx, rx, he->he_index, 1.0f);
        !           572:                update_history_data(&he->he_tx, tx, he->he_index, 1.0f);
        !           573:        /* The timing code might do shorter intervals than requested to
        !           574:         * adjust previous intervals being too long */
        !           575:        } else if (diff >= ((1.0f - get_hb_factor()) * unit)) {
        !           576:                update_history_data(&he->he_rx, rx, he->he_index, diff);
        !           577:                update_history_data(&he->he_tx, tx, he->he_index, diff);
        !           578:        } else {
        !           579:                /* Silently discard and give it a chance to come back
        !           580:                 * in time. */
        !           581:                return;
        !           582:        }
        !           583: 
        !           584:        if (he->he_index >= (HISTORY_SIZE - 1))
        !           585:                he->he_index = 0;
        !           586:        else
        !           587:                he->he_index++;
        !           588: 
        !           589:        COPY_TS(&he->he_last_update, ts);
        !           590: 
        !           591:        return;
        !           592: discard:
        !           593:        while(diff > 0.0f) {
        !           594:                he->he_rx.hd_data[he->he_index] = UNK_DATA;
        !           595:                he->he_tx.hd_data[he->he_index] = UNK_DATA;
        !           596: 
        !           597:                if (he->he_index >= (HISTORY_SIZE - 1))
        !           598:                        he->he_index = 0;
        !           599:                else
        !           600:                        he->he_index++;
        !           601: 
        !           602:                diff -= unit;
        !           603:        }
        !           604: 
        !           605:        he->he_rx.hd_prev_total = rx->r_total;
        !           606:        he->he_tx.hd_prev_total = tx->r_total;
        !           607: 
        !           608:        he->he_rx.hd_overflows = rx->r_overflows;
        !           609:        he->he_tx.hd_overflows = tx->r_overflows;
        !           610:        COPY_TS(&he->he_last_update, ts);
        !           611: 
        !           612: }
        !           613: 
        !           614: static inline void update_history(history_t *hist, rate_t *rx, rate_t *tx,
        !           615:                                  timestamp_t *ts)
        !           616: {
        !           617:        if (get_read_interval() != 1.0f)
        !           618:                update_history_element(&hist->h_read, rx, tx, ts,
        !           619:                    get_read_interval());
        !           620:        update_history_element(&hist->h_sec, rx, tx, ts, SECOND);
        !           621:        update_history_element(&hist->h_min, rx, tx, ts, MINUTE);
        !           622:        update_history_element(&hist->h_hour, rx, tx, ts, HOUR);
        !           623:        update_history_element(&hist->h_day, rx, tx, ts, DAY);
        !           624: }
        !           625: 
        !           626: static void update_attr_hist(stat_attr_t *a, void *arg)
        !           627: {
        !           628:        timestamp_t *ts = (timestamp_t *) arg;
        !           629:        int ign_of = a->a_flags & ATTR_FLAG_IGNORE_OVERFLOWS;
        !           630: 
        !           631:        if (ts == NULL)
        !           632:                ts = &rtiming.rt_last_read;
        !           633: 
        !           634:        if (a->a_flags & ATTR_FLAG_IS_RATE) {
        !           635:                a->a_rx.r_tps = a->a_rx.r_total;
        !           636:                a->a_tx.r_tps = a->a_tx.r_total;
        !           637:        } else {
        !           638:                calc_rate(&a->a_rx, ts, ign_of);
        !           639:                calc_rate(&a->a_tx, ts, ign_of);
        !           640:        }
        !           641: 
        !           642:        if (a->a_flags & ATTR_FLAG_HISTORY) {
        !           643:                stat_attr_hist_t *ah = (stat_attr_hist_t *) a;
        !           644:                update_history(&ah->a_hist, &ah->a_rx, &ah->a_tx, ts);
        !           645:        }
        !           646: }
        !           647: 
        !           648: void notify_update(item_t *i, timestamp_t *ts)
        !           649: {
        !           650:        struct it_item *tab;
        !           651:        stat_attr_t *a;
        !           652: 
        !           653:        i->i_flags |= ITEM_FLAG_UPDATED;
        !           654:        foreach_attr(i, &update_attr_hist, ts);
        !           655:        
        !           656:        a = lookup_attr(i, i->i_major_attr);
        !           657:        tab = lookup_tab(i);
        !           658: 
        !           659:        if (tab && a) {
        !           660:                rate_cnt_t rx = attr_get_rx_rate(a);
        !           661:                rate_cnt_t tx = attr_get_tx_rate(a);
        !           662: 
        !           663:                if (tab->ii_rx_max) {
        !           664:                        if (rx)
        !           665:                                i->i_rx_usage = (100.0f / (tab->ii_rx_max / rx));
        !           666:                        else
        !           667:                                i->i_rx_usage = 0;
        !           668:                } else
        !           669:                        i->i_rx_usage = -1;
        !           670: 
        !           671:                if (tab->ii_tx_max) {
        !           672:                        if (tx)
        !           673:                                i->i_tx_usage = (100.0f / (tab->ii_tx_max / tx));
        !           674:                        else
        !           675:                                i->i_tx_usage = 0;
        !           676:                } else
        !           677:                        i->i_tx_usage = -1;
        !           678:        } else if (!i->i_node || !i->i_node->n_from) {
        !           679:                i->i_rx_usage = -1;
        !           680:                i->i_tx_usage = -1;
        !           681:        }
        !           682: }
        !           683: 
        !           684: void increase_lifetime(item_t *i, int l)
        !           685: {
        !           686:        i->i_lifetime = l*get_lifetime();
        !           687: }
        !           688: 
        !           689: void update_attr(item_t *i, int type, b_cnt_t rx, b_cnt_t tx, int flags)
        !           690: {
        !           691:        stat_attr_t *a;
        !           692:        uint8_t h = attr_hash(type);
        !           693:        
        !           694:        for (a = i->i_attrs[h]; a; a = a->a_next)
        !           695:                if (a->a_type == type)
        !           696:                        goto found;
        !           697:        
        !           698:        if (collect_history(type)) {
        !           699:                a = xcalloc(1, sizeof(stat_attr_hist_t));
        !           700:                a->a_flags |= ATTR_FLAG_HISTORY;
        !           701:        } else
        !           702:                a = xcalloc(1, sizeof(stat_attr_t));
        !           703: 
        !           704:        a->a_type = type;
        !           705:        a->a_unit = attr_unit(a->a_type);
        !           706:        if (attr_ignore_overflows(a->a_type))
        !           707:                a->a_flags |= ATTR_FLAG_IGNORE_OVERFLOWS;
        !           708:        if (attr_is_rate(a->a_type))
        !           709:                a->a_flags |= ATTR_FLAG_IS_RATE;
        !           710: 
        !           711:        a->a_next = i->i_attrs[h];
        !           712:        i->i_attrs[h] = a;
        !           713:        i->i_nattrs++;
        !           714: 
        !           715: found:
        !           716:        if (flags & IS64BIT)
        !           717:                a->a_rx.r_is64bit = a->a_tx.r_is64bit = 1;
        !           718: 
        !           719:        if (flags & RX_PROVIDED) {
        !           720:                a->a_rx.r_total = rx;
        !           721:                a->a_flags |= ATTR_FLAG_RX_ENABLED;
        !           722:                update_ts(&a->a_updated); /* XXX: use read ts */
        !           723:        }
        !           724: 
        !           725:        if (flags & TX_PROVIDED) {
        !           726:                a->a_tx.r_total = tx;
        !           727:                a->a_flags |= ATTR_FLAG_TX_ENABLED;
        !           728:                update_ts(&a->a_updated);
        !           729:        }
        !           730: }
        !           731: 
        !           732: 
        !           733: item_t * get_item(node_t *node, int index)
        !           734: {
        !           735:        int i;
        !           736: 
        !           737:        for (i = 0; i < node->n_nitems; i++)
        !           738:                if (node->n_items[i].i_index == index)
        !           739:                        return &node->n_items[i];
        !           740:        return NULL;
        !           741: }
        !           742: 
        !           743: stat_attr_t *current_attr(int graph)
        !           744: {
        !           745:        int i, c;
        !           746:        item_t *it = get_current_item();
        !           747:        stat_attr_t *a;
        !           748: 
        !           749:        if (it == NULL)
        !           750:                return NULL;
        !           751: 
        !           752:        for (i = 0, c = 0; i < ATTR_HASH_MAX; i++)
        !           753:                for (a = it->i_attrs[i]; a; a = a->a_next, c++)
        !           754:                        if (c == it->i_attr_sel[graph])
        !           755:                                return a;
        !           756: 
        !           757:        return NULL;
        !           758: }
        !           759: 
        !           760: int first_attr(void)
        !           761: {
        !           762:        int i, c;
        !           763:        stat_attr_t *a;
        !           764:        item_t *it = get_current_item();
        !           765:        if (it == NULL)
        !           766:                return EMPTY_LIST;
        !           767: 
        !           768:        for (i = 0, c = 0; i < ATTR_HASH_MAX; i++) {
        !           769:                for (a = it->i_attrs[i]; a; a = a->a_next) {
        !           770:                        if (a->a_flags & ATTR_FLAG_HISTORY) {
        !           771:                                it->i_attr_sel[it->i_graph_sel] = c;
        !           772:                                return 0;
        !           773:                        } else
        !           774:                                c++;
        !           775:                }
        !           776:        }
        !           777: 
        !           778:        return EMPTY_LIST;
        !           779: }
        !           780: 
        !           781: int next_attr(void)
        !           782: {
        !           783:        item_t *it = get_current_item();
        !           784:        if (it == NULL)
        !           785:                return EMPTY_LIST;
        !           786: 
        !           787:        if (it->i_attr_sel[it->i_graph_sel] >= (it->i_nattrs - 1))
        !           788:                return first_attr();
        !           789:        else {
        !           790:                stat_attr_t *a = current_attr(it->i_graph_sel);
        !           791:                int i, n = it->i_attr_sel[it->i_graph_sel] + 1;
        !           792: 
        !           793:                if (a) {
        !           794:                        stat_attr_t *b = a->a_next;
        !           795:                        i = attr_hash(a->a_type);
        !           796:                        if (!b)
        !           797:                                i++;
        !           798:                        for (; i < ATTR_HASH_MAX; i++) {
        !           799:                                for (a = b ? : it->i_attrs[i]; a; a = a->a_next) {
        !           800:                                        if (!(a->a_flags & ATTR_FLAG_HISTORY)) {
        !           801:                                                n++;
        !           802:                                                continue;
        !           803:                                        }
        !           804:                                        b = NULL;
        !           805:                                        it->i_attr_sel[it->i_graph_sel] = n;
        !           806:                                        return 0;
        !           807:                                }
        !           808:                        }
        !           809:                }
        !           810:        
        !           811:                return first_attr();
        !           812:        }
        !           813: 
        !           814:        return 0;
        !           815: }
        !           816: 
        !           817: 
        !           818: int set_graph_unit(int unit)
        !           819: {
        !           820:        item_t *it = get_current_item();
        !           821:        if (it == NULL)
        !           822:                return EMPTY_LIST;
        !           823: 
        !           824:        it->i_unit[it->i_graph_sel] = unit;
        !           825: 
        !           826:        return 0;
        !           827: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>