1 /*
2  * attr.c		Attributes
3  *
4  * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
5  * Copyright (c) 2013 Red Hat, Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include <bmon/bmon.h>
27 #include <bmon/conf.h>
28 #include <bmon/attr.h>
29 #include <bmon/history.h>
30 #include <bmon/element.h>
31 #include <bmon/unit.h>
32 #include <bmon/input.h>
33 #include <bmon/utils.h>
34 
35 #if 0
36 
37 #define MAX_POLICY             255
38 
39 static char * allowed_attrs[MAX_POLICY];
40 static char * denied_attrs[MAX_POLICY];
41 static int allow_all_attrs;
42 
43 #endif
44 
45 static LIST_HEAD(attr_def_list);
46 static int attr_id_gen = 1;
47 
attr_def_lookup(const char * name)48 struct attr_def *attr_def_lookup(const char *name)
49 {
50 	struct attr_def *def;
51 
52 	list_for_each_entry(def, &attr_def_list, ad_list)
53 		if (!strcmp(name, def->ad_name))
54 			return def;
55 
56 	return NULL;
57 }
58 
attr_def_lookup_id(int id)59 struct attr_def *attr_def_lookup_id(int id)
60 {
61 	struct attr_def *def;
62 
63 	list_for_each_entry(def, &attr_def_list, ad_list)
64 		if (def->ad_id == id)
65 			return def;
66 
67 	return NULL;
68 }
69 
70 #if 0
71 int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg)
72 {
73 	int i, err = 0;
74 
75 	for (i = 0; i < NAME_HASHSIZ; i++) {
76 		struct attr_type *t;
77 		for (t = attr_ht_name[i]; t; t = t->at_next_name) {
78 			err = cb(t, arg);
79 			if (err < 0)
80 				break;
81 		}
82 	}
83 
84 	return err;
85 }
86 #endif
87 
attr_def_add(const char * name,const char * desc,struct unit * unit,int type,int flags)88 int attr_def_add(const char *name, const char *desc, struct unit *unit,
89 		 int type, int flags)
90 {
91 	struct attr_def *def;
92 
93 	if ((def = attr_def_lookup(name)))
94 		return def->ad_id;
95 
96 	def = xcalloc(1, sizeof(*def));
97 
98 	def->ad_id = attr_id_gen++;
99 	def->ad_name = strdup(name);
100 
101 	def->ad_description = strdup(desc ? : "");
102 	def->ad_type = type;
103 	def->ad_unit = unit;
104 	def->ad_flags = flags;
105 
106 	list_add_tail(&def->ad_list, &attr_def_list);
107 
108 	DBG("New attribute %s desc=\"%s\" unit=%s type=%d",
109 	    def->ad_name, def->ad_description, def->ad_unit->u_name, type);
110 
111 	return def->ad_id;
112 }
113 
attr_def_free(struct attr_def * def)114 static void attr_def_free(struct attr_def *def)
115 {
116 	if (!def)
117 		return;
118 
119 	xfree(def->ad_name);
120 	xfree(def->ad_description);
121 	xfree(def);
122 }
123 
attr_map_load(struct attr_map * map,size_t size)124 int attr_map_load(struct attr_map *map, size_t size)
125 {
126 	int i, nfailed = 0;
127 
128 	for (i = 0; i < size; i++) {
129 		struct attr_map *m = &map[i];
130 		struct unit *u;
131 
132 		if (!(u = unit_lookup(m->unit))) {
133 			nfailed++;
134 			continue;
135 		}
136 
137 		m->attrid = attr_def_add(m->name, m->description, u,
138 					 m->type, m->flags);
139 	}
140 
141 	return nfailed;
142 }
143 
attr_hash(int id)144 static inline unsigned int attr_hash(int id)
145 {
146 	return id % ATTR_HASH_SIZE;
147 }
148 
attr_lookup(const struct element * e,int id)149 struct attr *attr_lookup(const struct element *e, int id)
150 {
151 	unsigned int hash = attr_hash(id);
152 	struct attr *attr;
153 
154 	list_for_each_entry(attr, &e->e_attrhash[hash], a_list)
155 		if (attr->a_def->ad_id == id)
156 			return attr;
157 
158 	return NULL;
159 }
160 
collect_history(struct element * e,struct attr_def * def)161 static int collect_history(struct element *e, struct attr_def *def)
162 {
163 	int n;
164 
165 	if (def->ad_flags & ATTR_FORCE_HISTORY)
166 		return 1;
167 
168 	for (n = 0; n <= GT_MAX; n++)
169 		if (e->e_key_attr[n] == def)
170 			return 1;
171 
172 	return 0;
173 #if 0
174 	if (!allowed_attrs[0] && !denied_attrs[0]) {
175 		if (!strcmp(ad->ad_name, "bytes") ||
176 		    !strcmp(ad->ad_name, "packets"))
177 			return 1;
178 		else
179 			return 0;
180 	}
181 
182 	if (!allowed_attrs[0]) {
183 		for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
184 			if (!strcasecmp(denied_attrs[n], ad->ad_name))
185 				return 0;
186 		return 1;
187 	}
188 
189 	for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
190 		if (!strcasecmp(denied_attrs[n], ad->ad_name))
191 			return 0;
192 
193 	for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++)
194 		if (!strcasecmp(allowed_attrs[n], ad->ad_name))
195 			return 1;
196 #endif
197 }
198 
199 #if 0
200 
201 void attr_parse_policy(const char *policy)
202 {
203 	static int set = 0;
204 	int i, a = 0, d = 0, f = 0;
205 	char *p, *s;
206 
207 	if (set)
208 		return;
209 	set = 1;
210 
211 	if (!strcasecmp(policy, "all")) {
212 		allow_all_attrs = 1;
213 		return ;
214 	}
215 
216 	s = strdup(policy);
217 
218 	for (i = 0, p = s; ; i++) {
219 		if (s[i] == ',' || s[i] == '\0') {
220 
221 			f = s[i] == '\0' ? 1 : 0;
222 			s[i] = '\0';
223 
224 			if ('!' == *p) {
225 				if (d > (MAX_POLICY - 1))
226 					break;
227 				denied_attrs[d++] = strdup(++p);
228 			} else {
229 				if(a > (MAX_POLICY - 1))
230 					break;
231 				allowed_attrs[a++] = strdup(p);
232 			}
233 
234 			if (f)
235 				break;
236 
237 			p = &s[i+1];
238 		}
239 	}
240 
241 	xfree(s);
242 }
243 
244 #endif
245 
attr_start_collecting_history(struct attr * attr)246 void attr_start_collecting_history(struct attr *attr)
247 {
248 	if (attr->a_flags & ATTR_DOING_HISTORY)
249 		return;
250 
251 	DBG("Starting to collect history for attribute %s",
252 	    attr->a_def->ad_name);
253 
254 	history_attach(attr);
255 	attr->a_flags |= ATTR_DOING_HISTORY;
256 }
257 
attrcmp(struct element * e,struct attr * a,struct attr * b)258 static int attrcmp(struct element *e, struct attr *a, struct attr *b)
259 {
260 	/* major key attribute is always first */
261 	if (e->e_key_attr[GT_MAJOR] == b->a_def)
262 		return 1;
263 
264 	/* minor key attribte is always second */
265 	if (e->e_key_attr[GT_MINOR] == b->a_def)
266 		return (e->e_key_attr[GT_MAJOR] == a->a_def) ? -1 : 1;
267 
268 	/* otherwise sort by alphabet */
269 	return strcasecmp(a->a_def->ad_description, b->a_def->ad_description);
270 }
271 
attr_update(struct element * e,int id,uint64_t rx,uint64_t tx,int flags)272 void attr_update(struct element *e, int id, uint64_t rx, uint64_t tx, int flags)
273 {
274 	struct attr *attr, *n;
275 	int update_ts = 0;
276 
277 	if (!(attr = attr_lookup(e, id))) {
278 		unsigned int hash = attr_hash(id);
279 		struct attr_def *def;
280 
281 		if (!(def = attr_def_lookup_id(id)))
282 			return;
283 
284 		DBG("Tracking new attribute %d (\"%s\") of element %s",
285 		    def->ad_id, def->ad_name, e->e_name);
286 
287 		attr = xcalloc(1, sizeof(*attr));
288 		attr->a_def = def;
289 		attr->a_flags = def->ad_flags;
290 
291 		init_list_head(&attr->a_history_list);
292 
293 		if (collect_history(e, def))
294 			attr_start_collecting_history(attr);
295 
296 		list_add_tail(&attr->a_list, &e->e_attrhash[hash]);
297 		e->e_nattrs++;
298 
299 		list_for_each_entry(n, &e->e_attr_sorted, a_sort_list) {
300 			if (attrcmp(e, attr, n) < 0) {
301 				list_add_tail(&attr->a_sort_list,
302 					      &n->a_sort_list);
303 				goto inserted;
304 			}
305 		}
306 
307 		list_add_tail(&attr->a_sort_list, &e->e_attr_sorted);
308 	}
309 
310 inserted:
311 	if (flags & UPDATE_FLAG_RX) {
312 		attr->a_rx_rate.r_current = rx;
313 		attr->a_flags |= ATTR_RX_ENABLED;
314 		update_ts = 1;
315 	}
316 
317 	if (flags & UPDATE_FLAG_TX) {
318 		attr->a_tx_rate.r_current = tx;
319 		attr->a_flags |= ATTR_TX_ENABLED;
320 		update_ts = 1;
321 	}
322 
323 	if (update_ts)
324 		update_timestamp(&attr->a_last_update);
325 
326 	DBG("Updated attribute %d (\"%s\") of element %s", id, attr->a_def->ad_name, e->e_name);
327 }
328 
attr_free(struct attr * a)329 void attr_free(struct attr *a)
330 {
331 	struct history *h, *n;
332 
333 	list_for_each_entry_safe(h, n, &a->a_history_list, h_list)
334 		history_free(h);
335 
336 	list_del(&a->a_list);
337 
338 	xfree(a);
339 }
340 
attr_rate2float(struct attr * a,double * rx,char ** rxu,int * rxprec,double * tx,char ** txu,int * txprec)341 void attr_rate2float(struct attr *a, double *rx, char **rxu, int *rxprec,
342 				     double *tx, char **txu, int *txprec)
343 {
344 	struct unit *u = a->a_def->ad_unit;
345 
346 	*rx = unit_value2str(a->a_rx_rate.r_rate, u, rxu, rxprec);
347 	*tx = unit_value2str(a->a_tx_rate.r_rate, u, txu, txprec);
348 }
349 
attr_select_first(void)350 struct attr *attr_select_first(void)
351 {
352 	struct element *e;
353 
354 	if (!(e = element_current()))
355 		return NULL;
356 
357 	if (list_empty(&e->e_attr_sorted))
358 		e->e_current_attr = NULL;
359 	else
360 		e->e_current_attr = list_first_entry(&e->e_attr_sorted,
361 					struct attr, a_sort_list);
362 
363 	return e->e_current_attr;
364 }
365 
attr_select_last(void)366 struct attr *attr_select_last(void)
367 {
368 	struct element *e;
369 
370 	if (!(e = element_current()))
371 		return NULL;
372 
373 	if (list_empty(&e->e_attr_sorted))
374 		e->e_current_attr = NULL;
375 	else
376 		e->e_current_attr = list_entry(&e->e_attr_sorted,
377 					   struct attr, a_sort_list);
378 
379 	return e->e_current_attr;
380 }
381 
attr_select_next(void)382 struct attr *attr_select_next(void)
383 {
384 	struct element *e;
385 	struct attr *a;
386 
387 	if (!(e = element_current()))
388 		return NULL;
389 
390 	if (!(a = e->e_current_attr))
391 		return attr_select_first();
392 
393 	if (a->a_sort_list.next != &e->e_attr_sorted)
394 		e->e_current_attr = list_entry(a->a_sort_list.next,
395 					   struct attr, a_sort_list);
396 	else
397 		return attr_select_first();
398 
399 	return e->e_current_attr;
400 }
401 
attr_select_prev(void)402 struct attr *attr_select_prev(void)
403 {
404 	struct element *e;
405 	struct attr *a;
406 
407 	if (!(e = element_current()))
408 		return NULL;
409 
410 	if (!(a = e->e_current_attr))
411 		return attr_select_last();
412 
413 	if (a->a_sort_list.prev != &e->e_attr_sorted)
414 		e->e_current_attr = list_entry(a->a_sort_list.prev,
415 					   struct attr, a_sort_list);
416 	else
417 		return attr_select_last();
418 
419 	return e->e_current_attr;
420 
421 }
422 
attr_current(void)423 struct attr *attr_current(void)
424 {
425 	struct element *e;
426 
427 	if (!(e = element_current()))
428 		return NULL;
429 
430 	if (!e->e_current_attr)
431 		return attr_select_first();
432 
433 	return e->e_current_attr;
434 }
435 
436 #if 0
437 int __first_attr(struct item *item, int graph)
438 {
439 	int i;
440 	struct attr *a;
441 
442 	for (i = 0; i < ATTR_HASH_MAX; i++) {
443 		for (a = item->i_attrs[i]; a; a = a->a_next) {
444 			if (a->a_flags & ATTR_FLAG_HISTORY) {
445 				item->i_attr_sel[graph] = a;
446 				return 0;
447 			}
448 		}
449 	}
450 
451 	return EMPTY_LIST;
452 }
453 
454 int __next_attr(struct item *item, int graph)
455 {
456 	int hash;
457 	struct attr *attr, *next;
458 
459 	if (item->i_attr_sel[graph] == NULL)
460 		return __first_attr(item, graph);
461 
462 	attr = item->i_attr_sel[graph];
463 	hash = attr_hash(attr->a_def->ad_id);
464 	next = attr->a_next;
465 
466 	if (next == NULL)
467 		hash++;
468 
469 	for (; hash < ATTR_HASH_MAX; hash++) {
470 		if (next) {
471 			attr = next;
472 			next = NULL;
473 		} else
474 			attr = item->i_attrs[hash];
475 
476 		for (; attr; attr = attr->a_next) {
477 			if (!(attr->a_flags & ATTR_FLAG_HISTORY))
478 				continue;
479 			item->i_attr_sel[graph] = attr;
480 			return 0;
481 		}
482 	}
483 
484 	return __first_attr(item, graph);
485 }
486 
487 struct attr *attr_current(struct item *item, int graph)
488 {
489 	if (item->i_attr_sel[graph] == NULL)
490 		__first_attr(item, graph);
491 
492 	return item->i_attr_sel[graph];
493 }
494 
495 int attr_first(void)
496 {
497 	struct item *item = item_current();
498 
499 	if (item == NULL)
500 		return EMPTY_LIST;
501 
502 	return __first_attr(item, item->i_graph_sel);
503 }
504 
505 int attr_next(void)
506 {
507 	struct item *item = item_current();
508 
509 	if (item == NULL)
510 		return EMPTY_LIST;
511 
512 	return __next_attr(item, item->i_graph_sel);
513 }
514 #endif
515 
__calc_usage(double rate,uint64_t max)516 static float __calc_usage(double rate, uint64_t max)
517 {
518 	if (!max)
519 		return FLT_MAX;
520 
521 	if (!rate)
522 		return 0.0f;
523 
524 	return 100.0f / ((double) max / (rate * cfg_rate_interval));
525 }
526 
rate_get_total(struct rate * r)527 uint64_t rate_get_total(struct rate *r)
528 {
529 	return r->r_total - r->r_reset;
530 }
531 
attr_calc_usage(struct attr * a,float * rx,float * tx,uint64_t rxmax,uint64_t txmax)532 void attr_calc_usage(struct attr *a, float *rx, float *tx,
533 		     uint64_t rxmax, uint64_t txmax)
534 {
535 	if (a->a_def->ad_type == ATTR_TYPE_PERCENT) {
536 		*rx = a->a_rx_rate.r_total;
537 		*tx = a->a_tx_rate.r_total;
538 	} else {
539 		*rx = __calc_usage(a->a_rx_rate.r_rate, rxmax);
540 		*tx = __calc_usage(a->a_tx_rate.r_rate, txmax);
541 	}
542 }
543 
calc_counter_rate(struct attr * a,struct rate * rate,timestamp_t * ts)544 static void calc_counter_rate(struct attr *a, struct rate *rate,
545 			      timestamp_t *ts)
546 {
547 	uint64_t delta, prev_total;
548 	float diff, old_rate;
549 
550 	if (rate->r_current < rate->r_prev) {
551 		/* Overflow detected */
552 		if (a->a_flags & ATTR_IGNORE_OVERFLOWS)
553 			delta = rate->r_current;
554 		else {
555 			if (a->a_flags & ATTR_TRUE_64BIT)
556 				delta = 0xFFFFFFFFFFFFFFFFULL - rate->r_prev;
557 			else
558 				delta = 0xFFFFFFFFULL - rate->r_prev;
559 
560 			delta += rate->r_current + 1;
561 		}
562 	} else
563 		delta = rate->r_current - rate->r_prev;
564 
565 	prev_total = rate->r_total;
566 	rate->r_total += delta;
567 	rate->r_prev = rate->r_current;
568 
569 	if (!prev_total) {
570 		/*
571 		 * No previous records exists, reset time to now to
572 		 * avoid doing unnecessary calculation, this behaviour
573 		 * continues as long as the counter stays 0.
574 		 */
575 		goto out;
576 	}
577 
578 	diff = timestamp_diff(&rate->r_last_calc, ts);
579 	if (diff < (cfg_rate_interval - cfg_rate_variance))
580 		return;
581 
582 	old_rate = rate->r_rate;
583 
584 	if (rate->r_total < prev_total) {
585 		/* overflow */
586 		delta = 0xFFFFFFFFFFFFFFFFULL - prev_total;
587 		delta += rate->r_total + 1;
588 	} else
589 		delta = rate->r_total - prev_total;
590 
591 	rate->r_rate = delta / diff;
592 
593 	if (old_rate)
594 		rate->r_rate = ((rate->r_rate * 3.0f) + old_rate) / 4.0f;
595 
596 out:
597 	copy_timestamp(&rate->r_last_calc, ts);
598 }
599 
calc_rate_total(struct attr * a,struct rate * rate,timestamp_t * ts)600 static void calc_rate_total(struct attr *a, struct rate *rate, timestamp_t *ts)
601 {
602 	rate->r_prev = rate->r_rate = rate->r_total = rate->r_current;
603 	copy_timestamp(&rate->r_last_calc, ts);
604 }
605 
attr_notify_update(struct attr * a,timestamp_t * ts)606 void attr_notify_update(struct attr *a, timestamp_t *ts)
607 {
608 	switch (a->a_def->ad_type) {
609 	case ATTR_TYPE_RATE:
610 	case ATTR_TYPE_PERCENT:
611 		calc_rate_total(a, &a->a_rx_rate, ts);
612 		calc_rate_total(a, &a->a_tx_rate, ts);
613 		break;
614 
615 	case ATTR_TYPE_COUNTER:
616 		calc_counter_rate(a, &a->a_rx_rate, ts);
617 		calc_counter_rate(a, &a->a_tx_rate, ts);
618 		break;
619 	default:
620 		DBG("Attribute update of unknown type");
621 		break;
622 	}
623 
624 	if (a->a_flags & ATTR_DOING_HISTORY) {
625 		struct history *h;
626 
627 		DBG("Updating history of attribute %d (\"%s\")", a->a_def->ad_id, a->a_def->ad_name);
628 
629 		list_for_each_entry(h, &a->a_history_list, h_list)
630 			history_update(a, h, ts);
631 	}
632 }
633 
attr_reset_counter(struct attr * a)634 void attr_reset_counter(struct attr *a)
635 {
636 	if (a->a_def->ad_type == ATTR_TYPE_COUNTER) {
637 		a->a_rx_rate.r_reset = a->a_rx_rate.r_total;
638 		a->a_tx_rate.r_reset = a->a_tx_rate.r_total;
639 	}
640 }
641 
attr_exit(void)642 static void __exit attr_exit(void)
643 {
644 	struct attr_def *ad, *n;
645 
646 	list_for_each_entry_safe(ad, n, &attr_def_list, ad_list)
647 		attr_def_free(ad);
648 }
649