Annotation of embedaddon/bmon/src/item.c, revision 1.1.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>