1: /*
2: * src/element.c Elements
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/element.h>
29: #include <bmon/element_cfg.h>
30: #include <bmon/group.h>
31: #include <bmon/input.h>
32: #include <bmon/utils.h>
33:
34: static LIST_HEAD(allowed);
35: static LIST_HEAD(denied);
36:
37: static int match_mask(const struct policy *p, const char *str)
38: {
39: int i, n;
40: char c;
41:
42: if (!p || !str)
43: return 0;
44:
45: for (i = 0, n = 0; p->p_rule[i] != '\0'; i++) {
46: if (p->p_rule[i] == '*') {
47: c = tolower(p->p_rule[i + 1]);
48:
49: if (c == '\0')
50: return 1;
51:
52: while (tolower(str[n]) != c)
53: if (str[n++] == '\0')
54: return 0;
55: } else if (tolower(p->p_rule[i]) != tolower(str[n++]))
56: return 0;
57: }
58:
59: return str[n] == '\0' ? 1 : 0;
60: }
61:
62: int element_allowed(const char *name, struct element_cfg *cfg)
63: {
64: struct policy *p;
65:
66: if (cfg) {
67: if (cfg->ec_flags & ELEMENT_CFG_HIDE)
68: return 0;
69: else if (cfg->ec_flags & ELEMENT_CFG_SHOW)
70: return 1;
71: }
72:
73: list_for_each_entry(p, &denied, p_list)
74: if (match_mask(p, name))
75: return 0;
76:
77: if (!list_empty(&allowed)) {
78: list_for_each_entry(p, &allowed, p_list)
79: if (match_mask(p, name))
80: return 1;
81:
82: return 0;
83: }
84:
85: return 1;
86: }
87:
88: void element_parse_policy(const char *policy)
89: {
90: char *start, *copy, *save = NULL, *tok;
91: struct policy *p;
92:
93: if (!policy)
94: return;
95:
96: copy = strdup(policy);
97: start = copy;
98:
99: while ((tok = strtok_r(start, ",", &save)) != NULL) {
100: start = NULL;
101:
102: p = xcalloc(1, sizeof(*p));
103:
104: if (*tok == '!') {
105: p->p_rule = strdup(++tok);
106: list_add_tail(&p->p_list, &denied);
107: } else {
108: p->p_rule = strdup(tok);
109: list_add_tail(&p->p_list, &allowed);
110: }
111: }
112:
113: xfree(copy);
114: }
115:
116: static struct element *__lookup_element(struct element_group *group,
117: const char *name, uint32_t id,
118: struct element *parent)
119: {
120: struct list_head *list;
121: struct element *e;
122:
123: if (parent)
124: list = &parent->e_childs;
125: else
126: list = &group->g_elements;
127:
128: list_for_each_entry(e, list, e_list)
129: if (!strcmp(name, e->e_name) && e->e_id == id)
130: return e;
131:
132: return NULL;
133: }
134:
135: struct element *element_lookup(struct element_group *group, const char *name,
136: uint32_t id, struct element *parent, int flags)
137: {
138: struct element_cfg *cfg;
139: struct element *e;
140: int i;
141:
142: if (!group)
143: BUG();
144:
145: if ((e = __lookup_element(group, name, id, parent)))
146: return e;
147:
148: if (!(flags & ELEMENT_CREAT))
149: return NULL;
150:
151: cfg = element_cfg_lookup(name);
152: if (!element_allowed(name, cfg))
153: return NULL;
154:
155: DBG("Creating element %d \"%s\"", id, name);
156:
157: e = xcalloc(1, sizeof(*e));
158:
159: init_list_head(&e->e_list);
160: init_list_head(&e->e_childs);
161: init_list_head(&e->e_info_list);
162: init_list_head(&e->e_attr_sorted);
163:
164: for (i = 0; i < ATTR_HASH_SIZE; i++)
165: init_list_head(&e->e_attrhash[i]);
166:
167: e->e_name = strdup(name);
168: e->e_id = id;
169: e->e_parent = parent;
170: e->e_group = group;
171: e->e_lifecycles = get_lifecycles();
172: e->e_flags = ELEMENT_FLAG_CREATED;
173: e->e_cfg = cfg;
174:
175: if (e->e_cfg) {
176: if (e->e_cfg->ec_description)
177: element_update_info(e, "Description",
178: e->e_cfg->ec_description);
179:
180: element_set_rxmax(e, e->e_cfg->ec_rxmax);
181: element_set_txmax(e, e->e_cfg->ec_txmax);
182: }
183:
184: if (parent) {
185: DBG("Attached to parent %d \"%s\"", parent->e_id, parent->e_name);
186: list_add_tail(&e->e_list, &parent->e_childs);
187: } else {
188: DBG("Attached to group %s", group->g_name);
189: list_add_tail(&e->e_list, &group->g_elements);
190: }
191:
192: group->g_nelements++;
193:
194: return e;
195: }
196:
197: void element_free(struct element *e)
198: {
199: struct info *info, *ninfo;
200: struct element *c, *cnext;
201: struct attr *a, *an;
202: int i;
203:
204: list_for_each_entry_safe(c, cnext, &e->e_childs, e_list)
205: element_free(c);
206:
207: list_for_each_entry_safe(info, ninfo, &e->e_info_list, i_list) {
208: xfree(info->i_name);
209: xfree(info->i_value);
210: list_del(&info->i_list);
211: xfree(info);
212: }
213:
214: for (i = 0; i < ATTR_HASH_SIZE; i++)
215: list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list)
216: attr_free(a);
217:
218: if (e->e_group->g_current == e) {
219: element_select_prev();
220: if (e->e_group->g_current == e)
221: e->e_group->g_current = NULL;
222: }
223:
224: list_del(&e->e_list);
225: e->e_group->g_nelements--;
226:
227: xfree(e->e_name);
228: xfree(e);
229: }
230:
231: #if 0
232: if (item->i_group->g_selected == item) {
233: if (item_select_prev() == END_OF_LIST) {
234: if (group_select_prev() == END_OF_LIST) {
235: if (node_select_prev() != END_OF_LIST)
236: item_select_last();
237: } else
238: item_select_last();
239: }
240: }
241: #endif
242:
243: #if 0
244:
245: void item_delete(struct item *item)
246: {
247: int m;
248: struct item *child;
249:
250: for (m = 0; m < ATTR_HASH_MAX; m++) {
251: struct attr *a, *next;
252: for (a = item->i_attrs[m]; a; a = next) {
253: next = a->a_next;
254: xfree(a);
255: }
256: }
257:
258: if (item->i_group->g_selected == item) {
259: if (item_select_prev() == END_OF_LIST) {
260: if (group_select_prev() == END_OF_LIST) {
261: if (node_select_prev() != END_OF_LIST)
262: item_select_last();
263: } else
264: item_select_last();
265: }
266: }
267:
268: unlink_item(item);
269: item->i_group->g_nitems--;
270:
271: for (child = item->i_childs; child; child = child->i_next)
272: item_delete(child);
273:
274: if (item->i_path)
275: xfree(item->i_path);
276:
277: xfree(item);
278: }
279:
280: #endif
281:
282: void element_reset_update_flag(struct element_group *g,
283: struct element *e, void *arg)
284: {
285: DBG("Reseting update flag of %s", e->e_name);
286: e->e_flags &= ~ELEMENT_FLAG_UPDATED;
287: }
288:
289: /**
290: * Needs to be called after updating all attributes of an element
291: */
292: void element_notify_update(struct element *e, timestamp_t *ts)
293: {
294: struct attr *a;
295: int i;
296:
297: e->e_flags |= ELEMENT_FLAG_UPDATED;
298:
299: if (ts == NULL)
300: ts = &rtiming.rt_last_read;
301:
302: for (i = 0; i < ATTR_HASH_SIZE; i++)
303: list_for_each_entry(a, &e->e_attrhash[i], a_list)
304: attr_notify_update(a, ts);
305:
306: if (e->e_usage_attr && e->e_cfg &&
307: (a = attr_lookup(e, e->e_usage_attr->ad_id))) {
308: attr_calc_usage(a, &e->e_rx_usage, &e->e_tx_usage,
309: e->e_cfg->ec_rxmax, e->e_cfg->ec_txmax);
310: } else {
311: e->e_rx_usage = FLT_MAX;
312: e->e_tx_usage = FLT_MAX;
313: }
314: }
315:
316: void element_lifesign(struct element *e, int n)
317: {
318: e->e_lifecycles = n * get_lifecycles();
319: }
320:
321: void element_check_if_dead(struct element_group *g,
322: struct element *e, void *arg)
323: {
324: if (--(e->e_lifecycles) <= 0) {
325: element_free(e);
326: DBG("Deleting dead element %s", e->e_name);
327: }
328: }
329:
330: void element_foreach_attr(struct element *e,
331: void (*cb)(struct element *e,
332: struct attr *, void *),
333: void *arg)
334: {
335: struct attr *a;
336:
337: list_for_each_entry(a, &e->e_attr_sorted, a_sort_list)
338: cb(e, a, arg);
339: }
340:
341: int element_set_key_attr(struct element *e, const char *major,
342: const char * minor)
343: {
344: if (!(e->e_key_attr[GT_MAJOR] = attr_def_lookup(major)))
345: return -ENOENT;
346:
347: if (!(e->e_key_attr[GT_MINOR] = attr_def_lookup(minor)))
348: return -ENOENT;
349:
350: return 0;
351: }
352:
353: int element_set_usage_attr(struct element *e, const char *usage)
354: {
355: if (!(e->e_usage_attr = attr_def_lookup(usage)))
356: return -ENOENT;
357:
358: return 0;
359: }
360:
361: void element_pick_from_policy(struct element_group *g)
362: {
363: if (!list_empty(&allowed)) {
364: struct policy *p;
365:
366: list_for_each_entry(p, &allowed, p_list) {
367: struct element *e;
368:
369: list_for_each_entry(e, &g->g_elements, e_list) {
370: if (match_mask(p, e->e_name)) {
371: g->g_current = e;
372: return;
373: }
374: }
375: }
376: }
377:
378: element_select_first();
379: }
380:
381: struct element *element_current(void)
382: {
383: struct element_group *g;
384:
385: if (!(g = group_current()))
386: return NULL;
387:
388: /*
389: * If no element is picked yet, pick a default interface according to
390: * the selection policy.
391: */
392: if (!g->g_current)
393: element_pick_from_policy(g);
394:
395: return g->g_current;
396: }
397:
398: struct element *element_select_first(void)
399: {
400: struct element_group *g;
401:
402: if (!(g = group_current()))
403: return NULL;
404:
405: if (list_empty(&g->g_elements))
406: g->g_current = NULL;
407: else
408: g->g_current = list_first_entry(&g->g_elements,
409: struct element, e_list);
410:
411: return g->g_current;
412: }
413:
414: struct element *element_select_last(void)
415: {
416: struct element_group *g;
417:
418: if (!(g = group_current()))
419: return NULL;
420:
421: if (list_empty(&g->g_elements))
422: g->g_current = NULL;
423: else {
424: struct element *e;
425:
426: e = list_entry(g->g_elements.prev, struct element, e_list);
427:
428: while (!list_empty(&e->e_childs))
429: e = list_entry(e->e_childs.prev, struct element,
430: e_list);
431:
432: g->g_current = e;
433: }
434:
435: return g->g_current;
436: }
437:
438: struct element *element_select_next(void)
439: {
440: struct element_group *g;
441: struct element *e;
442:
443: if (!(g = group_current()))
444: return NULL;
445:
446: if (!(e = g->g_current))
447: return element_select_first();
448:
449: if (!list_empty(&e->e_childs))
450: e = list_first_entry(&e->e_childs, struct element, e_list);
451: else {
452: /*
453: * move upwards until we have no parent or there is a next
454: * entry in the list
455: */
456: while (e->e_parent && e->e_list.next == &e->e_parent->e_childs)
457: e = e->e_parent;
458:
459: if (!e->e_parent && e->e_list.next == &g->g_elements) {
460: group_select_next();
461: return element_select_first();
462: } else
463: e = list_entry(e->e_list.next, struct element, e_list);
464: }
465:
466: g->g_current = e;
467:
468: return e;
469: }
470:
471: struct element *element_select_prev(void)
472: {
473: struct element_group *g;
474: struct element *e;
475:
476: if (!(g = group_current()))
477: return NULL;
478:
479: if (!(e = g->g_current))
480: return element_select_last();
481:
482: if (!e->e_parent && e->e_list.prev == &g->g_elements) {
483: group_select_prev();
484: return element_select_last();
485: }
486:
487: if (e->e_parent && e->e_list.prev == &e->e_parent->e_childs)
488: e = e->e_parent;
489: else {
490: e = list_entry(e->e_list.prev, struct element, e_list);
491:
492: while (!list_empty(&e->e_childs))
493: e = list_entry(e->e_childs.prev, struct element,
494: e_list);
495: }
496:
497: g->g_current = e;
498:
499: return e;
500: }
501:
502: static struct info *element_info_lookup(struct element *e, const char *name)
503: {
504: struct info *i;
505:
506: list_for_each_entry(i, &e->e_info_list, i_list)
507: if (!strcmp(i->i_name, name))
508: return i;
509:
510: return NULL;
511: }
512:
513: void element_update_info(struct element *e, const char *name, const char *value)
514: {
515: struct info *i;
516:
517: if ((i = element_info_lookup(e, name))) {
518: xfree(i->i_value);
519: i->i_value = strdup(value);
520: return;
521: }
522:
523: DBG("Created element info %s (\"%s\")", name, value);
524:
525: i = xcalloc(1, sizeof(*i));
526: i->i_name = strdup(name);
527: i->i_value = strdup(value);
528:
529: e->e_ninfo++;
530:
531: list_add_tail(&i->i_list, &e->e_info_list);
532: }
533:
534: void element_set_txmax(struct element *e, uint64_t max)
535: {
536: char buf[32];
537:
538: if (!e->e_cfg)
539: e->e_cfg = element_cfg_create(e->e_name);
540:
541: if (e->e_cfg->ec_txmax != max)
542: e->e_cfg->ec_txmax = max;
543:
544: unit_bit2str(e->e_cfg->ec_txmax * 8, buf, sizeof(buf));
545: element_update_info(e, "TxMax", buf);
546: }
547:
548: void element_set_rxmax(struct element *e, uint64_t max)
549: {
550: char buf[32];
551:
552: if (!e->e_cfg)
553: e->e_cfg = element_cfg_create(e->e_name);
554:
555: if (e->e_cfg->ec_rxmax != max)
556: e->e_cfg->ec_rxmax = max;
557:
558: unit_bit2str(e->e_cfg->ec_rxmax * 8, buf, sizeof(buf));
559: element_update_info(e, "RxMax", buf);
560: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>