Annotation of embedaddon/bmon/src/in_netlink.c, revision 1.1.1.1
1.1 misho 1: /*
2: * in_netlink.c rtnetlink input (Linux)
3: *
4: * Copyright (c) 2001-2005 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/input.h>
27: #include <bmon/node.h>
28: #include <bmon/item.h>
29: #include <bmon/conf.h>
30: #include <bmon/utils.h>
31:
32: #if defined HAVE_NL && defined SYS_LINUX
33:
34: static int c_notc = 0;
35: static const char *c_mapfile;
36:
37: struct hmap {
38: char *id;
39: char *name;
40: struct hmap *next;
41: };
42:
43: static struct hmap *map;
44:
45: #include <netlink/netlink.h>
46: #include <netlink/cache.h>
47: #include <netlink/helpers.h>
48: #include <netlink/route/link.h>
49: #include <netlink/route/qdisc.h>
50: #include <netlink/route/class.h>
51: #include <netlink/route/filter.h>
52:
53: #include <net/if.h>
54:
55: static struct nl_handle nl_h = NL_INIT_HANDLE();
56: static struct nl_cache link_cache = RTNL_INIT_LINK_CACHE();
57: static struct nl_cache *qdisc_cache;
58: static struct nl_cache *class_cache;
59:
60: struct xdata {
61: item_t *intf;
62: struct rtnl_link *link;
63: int level;
64: item_t *parent;
65: };
66:
67: static void read_map(const char *file)
68: {
69: FILE *f;
70: char buf[1024];
71: int line = 0;
72:
73: f = fopen(file, "r");
74: if (f == NULL)
75: quit("Could not open mapfile %s: %s\n", file, strerror(errno));
76:
77: while (fgets(buf, sizeof(buf), f)) {
78: struct hmap *m;
79: char *p, *id, *name;
80: line++;
81: if (*buf == '#' || *buf == '\r' || *buf == '\n')
82: continue;
83:
84: for (p = buf; *p == ' ' || *p == '\t'; p++);
85: if (*p == '\0')
86: quit("%s: Parse error at line %d: Missing handle\n",
87: file, line);
88: id = p;
89:
90: for (; *p != ' ' && *p != '\t' && *p != '\0'; p++);
91: if (*p == '\0')
92: quit("%s: Parse error at line %d: Missing name\n",
93: file, line);
94: *p = '\0';
95:
96: for (++p; *p == ' ' || *p == '\t'; p++);
97: name = p;
98: for (; *p != ' ' && *p != '\t' && *p != '\0' &&
99: *p != '\r' && *p != '\n'; p++);
100: *p = '\0';
101:
102: if (strlen(id) <= 0 || strlen(name) <= 0)
103: quit("%s: Parse error at line %d: Invalid id or handle\n",
104: file, line);
105:
106: m = xcalloc(1, sizeof(*m));
107: m->id = strdup(id);
108: m->name = strdup(name);
109: m->next = map;
110: map = m;
111: }
112:
113: fclose(f);
114: }
115:
116: static const char *lookup_map(const char *handle)
117: {
118: struct hmap *m;
119:
120: for (m = map; m; m = m->next)
121: if (!strcmp(handle, m->id))
122: return m->name;
123:
124: return handle;
125: }
126:
127: static void handle_qdisc(struct nl_common *, void *);
128:
129: #if 0
130: static void handle_filter(struct nl_common *c, void *arg)
131: {
132: struct rtnl_filter *filter = (struct rtnl_filter *) c;
133: struct xdata *x = arg;
134: item_t *intf;
135: char name[IFNAME_MAX];
136:
137: printf("HAHAH!\n");
138:
139: if (filter->f_handle) {
140: const char *h = lookup_map(nl_handle2str(filter->f_handle));
141: snprintf(name, sizeof(name), "f:%s %s", filter->f_kind, h);
142: } else
143: snprintf(name, sizeof(name), "f:%s", filter->f_kind);
144:
145: intf = lookup_item(get_local_node(), name, filter->f_handle, x->parent);
146:
147: if (intf == NULL)
148: return;
149:
150: intf->i_link = x->intf->i_index;
151: intf->i_flags |= ITEM_FLAG_IS_CHILD;
152: intf->i_level = x->level;
153:
154: update_attr(intf, PACKETS, 0, 0, 0);
155: update_attr(intf, BYTES, 0, 0, 0);
156:
157: notify_update(intf, NULL);
158: increase_lifetime(intf, 1);
159: }
160: #endif
161:
162: static void handle_class(struct nl_common *c, void *arg)
163: {
164: struct rtnl_class *class = (struct rtnl_class *) c;
165: struct rtnl_qdisc *leaf;
166: struct xdata *x = arg;
167: item_t *intf;
168: char name[IFNAME_MAX];
169: struct xdata xn = {
170: .intf = x->intf,
171: .link = x->link,
172: .level = x->level + 1,
173: };
174:
175: if (class->c_handle) {
176: const char *h = lookup_map(nl_handle2str(class->c_handle));
177: snprintf(name, sizeof(name), "c:%s(%s)", class->c_kind, h);
178: } else
179: snprintf(name, sizeof(name), "c:%s", class->c_kind);
180:
181: intf = lookup_item(get_local_node(), name, class->c_handle, x->parent);
182:
183: if (intf == NULL)
184: return;
185:
186: xn.parent = intf;
187:
188: intf->i_link = x->intf->i_index;
189: intf->i_flags |= ITEM_FLAG_IS_CHILD;
190: intf->i_level = x->level;
191: intf->i_major_attr = BYTES;
192: intf->i_minor_attr = PACKETS;
193:
194: update_attr(intf, PACKETS, 0, class->c_stats.tcs_basic.packets, TX_PROVIDED);
195: update_attr(intf, BYTES, 0, class->c_stats.tcs_basic.bytes, TX_PROVIDED);
196: update_attr(intf, DROP, 0, class->c_stats.tcs_queue.drops, TX_PROVIDED);
197: update_attr(intf, OVERLIMITS, 0, class->c_stats.tcs_queue.overlimits, TX_PROVIDED);
198: update_attr(intf, BPS, 0, class->c_stats.tcs_rate_est.bps, TX_PROVIDED);
199: update_attr(intf, PPS, 0, class->c_stats.tcs_rate_est.pps, TX_PROVIDED);
200: update_attr(intf, QLEN, 0, class->c_stats.tcs_queue.qlen, TX_PROVIDED);
201: update_attr(intf, BACKLOG, 0, class->c_stats.tcs_queue.backlog, TX_PROVIDED);
202: update_attr(intf, REQUEUES, 0, class->c_stats.tcs_queue.requeues, TX_PROVIDED);
203:
204: notify_update(intf, NULL);
205: increase_lifetime(intf, 1);
206:
207: if ((leaf = rtnl_class_leaf_qdisc(class, qdisc_cache)))
208: handle_qdisc((struct nl_common *) leaf, &xn);
209: rtnl_class_foreach_child(class, class_cache, &handle_class, &xn);
210: #if 0
211: rtnl_class_foreach_filter_nocache(&nl_h, class, &handle_filter, &xn);
212: #endif
213: }
214:
215: static void handle_qdisc(struct nl_common *c, void *arg)
216: {
217: struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) c;
218: struct xdata *x = arg;
219: item_t *intf;
220: char name[IFNAME_MAX];
221: struct xdata xn = {
222: .intf = x->intf,
223: .link = x->link,
224: .level = x->level + 1,
225: };
226:
227: if (qdisc->q_handle) {
228: const char *h = lookup_map(nl_handle2str(qdisc->q_handle));
229: snprintf(name, sizeof(name), "q:%s(%s)", qdisc->q_kind, h);
230: } else
231: snprintf(name, sizeof(name), "q:%s", qdisc->q_kind);
232:
233: intf = lookup_item(get_local_node(), name, qdisc->q_handle, x->parent);
234: if (intf == NULL)
235: return;
236:
237: xn.parent = intf;
238:
239: intf->i_link = x->intf->i_index;
240: intf->i_flags |= ITEM_FLAG_IS_CHILD;
241: intf->i_level = x->level;
242: intf->i_major_attr = BYTES;
243: intf->i_minor_attr = PACKETS;
244:
245: if (qdisc->q_handle == 0xffff00) {
246: update_attr(intf, BYTES, qdisc->q_stats.tcs_basic.bytes, 0, RX_PROVIDED);
247: update_attr(intf, PACKETS, qdisc->q_stats.tcs_basic.packets, 0, RX_PROVIDED);
248: update_attr(intf, DROP, qdisc->q_stats.tcs_queue.drops, 0, RX_PROVIDED);
249: update_attr(intf, OVERLIMITS, qdisc->q_stats.tcs_queue.overlimits, 0, RX_PROVIDED);
250: update_attr(intf, BPS, qdisc->q_stats.tcs_rate_est.bps, 0, RX_PROVIDED);
251: update_attr(intf, PPS, qdisc->q_stats.tcs_rate_est.pps, 0, RX_PROVIDED);
252: update_attr(intf, QLEN, qdisc->q_stats.tcs_queue.qlen, 0, RX_PROVIDED);
253: update_attr(intf, BACKLOG, qdisc->q_stats.tcs_queue.backlog, 0, RX_PROVIDED);
254: update_attr(intf, REQUEUES, qdisc->q_stats.tcs_queue.requeues, 0, RX_PROVIDED);
255: } else {
256: update_attr(intf, BYTES, 0, qdisc->q_stats.tcs_basic.bytes, TX_PROVIDED);
257: update_attr(intf, PACKETS, 0, qdisc->q_stats.tcs_basic.packets, TX_PROVIDED);
258: update_attr(intf, DROP, 0, qdisc->q_stats.tcs_queue.drops, TX_PROVIDED);
259: update_attr(intf, OVERLIMITS, 0, qdisc->q_stats.tcs_queue.overlimits, TX_PROVIDED);
260: update_attr(intf, BPS, 0, qdisc->q_stats.tcs_rate_est.bps, TX_PROVIDED);
261: update_attr(intf, PPS, 0, qdisc->q_stats.tcs_rate_est.pps, TX_PROVIDED);
262: update_attr(intf, QLEN, 0, qdisc->q_stats.tcs_queue.qlen, TX_PROVIDED);
263: update_attr(intf, BACKLOG, 0, qdisc->q_stats.tcs_queue.backlog, TX_PROVIDED);
264: update_attr(intf, REQUEUES, 0, qdisc->q_stats.tcs_queue.requeues, TX_PROVIDED);
265: }
266:
267: notify_update(intf, NULL);
268: increase_lifetime(intf, 1);
269:
270: rtnl_qdisc_foreach_child(qdisc, class_cache, &handle_class, &xn);
271: #if 0
272: rtnl_qdisc_foreach_filter_nocache(&nl_h, qdisc, &handle_filter, &xn);
273: #endif
274: }
275:
276: static void handle_tc(item_t *intf, struct rtnl_link *link)
277: {
278: struct rtnl_qdisc *qdisc;
279: struct xdata x = {
280: .intf = intf,
281: .link = link,
282: .level = 1,
283: .parent = intf,
284: };
285:
286: class_cache = rtnl_class_build_cache(&nl_h, link->l_index);
287: if (class_cache == NULL)
288: return;
289:
290: if ((qdisc = rtnl_qdisc_get_root(qdisc_cache, link->l_index)))
291: handle_qdisc((struct nl_common *) qdisc, &x);
292: else if ((qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, link->l_index, 0)))
293: handle_qdisc((struct nl_common *) qdisc, &x);
294:
295: if ((qdisc = rtnl_qdisc_get_ingress(qdisc_cache, link->l_index)))
296: handle_qdisc((struct nl_common *) qdisc, &x);
297:
298: nl_cache_destroy_and_free(class_cache);
299: }
300:
301: static void do_link(struct nl_common *item, void *arg)
302: {
303: struct rtnl_link *link = (struct rtnl_link *) item;
304: struct rtnl_lstats *st;
305: item_t *intf;
306:
307: if (!link->l_name[0])
308: return;
309:
310: if (get_show_only_running() && !(link->l_flags & IFF_UP))
311: return;
312:
313: intf = lookup_item(get_local_node(), link->l_name, 0, 0);
314:
315: if (NULL == intf)
316: return;
317:
318: intf->i_major_attr = BYTES;
319: intf->i_minor_attr = PACKETS;
320:
321: st = &link->l_stats;
322:
323: update_attr(intf, BYTES, st->ls_rx.bytes, st->ls_tx.bytes,
324: RX_PROVIDED | TX_PROVIDED);
325: update_attr(intf, PACKETS, st->ls_rx.packets, st->ls_tx.packets,
326: RX_PROVIDED | TX_PROVIDED);
327:
328: update_attr(intf, ERRORS, st->ls_rx.errors, st->ls_tx.errors,
329: RX_PROVIDED | TX_PROVIDED);
330:
331: update_attr(intf, DROP, st->ls_rx.dropped, st->ls_tx.dropped,
332: RX_PROVIDED | TX_PROVIDED);
333:
334: update_attr(intf, FIFO, st->ls_rx_fifo_errors,
335: st->ls_tx_fifo_errors, RX_PROVIDED | TX_PROVIDED);
336:
337: update_attr(intf, COMPRESSED, st->ls_rx.compressed,
338: st->ls_tx.compressed, RX_PROVIDED | TX_PROVIDED);
339:
340: update_attr(intf, MULTICAST, st->ls_rx.multicast, 0, RX_PROVIDED);
341: update_attr(intf, COLLISIONS, 0, st->ls_tx_collisions, TX_PROVIDED);
342: update_attr(intf, LENGTH_ERRORS, st->ls_rx_length_errors, 0, RX_PROVIDED);
343: update_attr(intf, OVER_ERRORS, st->ls_rx_over_errors, 0, RX_PROVIDED);
344: update_attr(intf, CRC_ERRORS, st->ls_rx_crc_errors, 0, RX_PROVIDED);
345: update_attr(intf, FRAME, st->ls_rx_frame_errors, 0, RX_PROVIDED);
346: update_attr(intf, MISSED_ERRORS, st->ls_rx_missed_errors, 0, RX_PROVIDED);
347: update_attr(intf, ABORTED_ERRORS, 0, st->ls_tx_aborted_errors, TX_PROVIDED);
348: update_attr(intf, HEARTBEAT_ERRORS, 0, st->ls_tx_heartbeat_errors,
349: TX_PROVIDED);
350: update_attr(intf, WINDOW_ERRORS, 0, st->ls_tx_window_errors, TX_PROVIDED);
351: update_attr(intf, CARRIER_ERRORS, 0, st->ls_tx_carrier_errors, TX_PROVIDED);
352:
353: if (!c_notc)
354: handle_tc(intf, link);
355:
356: notify_update(intf, NULL);
357: increase_lifetime(intf, 1);
358: }
359:
360: static void netlink_read(void)
361: {
362: if (nl_cache_update(&nl_h, &link_cache) < 0)
363: quit("%s\n", nl_geterror());
364:
365: if (!c_notc) {
366: if (qdisc_cache == NULL) {
367: qdisc_cache = rtnl_qdisc_build_cache(&nl_h);
368: if (qdisc_cache == NULL)
369: c_notc = 1;
370: } else {
371: if (nl_cache_update(&nl_h, qdisc_cache) < 0)
372: c_notc = 1;
373: }
374: }
375:
376: nl_cache_foreach(&link_cache, do_link, NULL);
377: }
378:
379: static void netlink_shutdown(void)
380: {
381: nl_close(&nl_h);
382: }
383:
384: static void netlink_do_init(void)
385: {
386: if (nl_connect(&nl_h, NETLINK_ROUTE) < 0)
387: quit("%s\n", nl_geterror());
388:
389: nl_use_default_handlers(&nl_h);
390: }
391:
392: static int netlink_probe(void)
393: {
394: if (nl_connect(&nl_h, NETLINK_ROUTE) < 0)
395: return 0;
396:
397: if (nl_cache_update(&nl_h, &link_cache) < 0) {
398: nl_close(&nl_h);
399: return 0;
400: }
401:
402: nl_cache_destroy(&link_cache);
403: nl_close(&nl_h);
404:
405: if (c_mapfile)
406: read_map(c_mapfile);
407:
408: return 1;
409: }
410:
411: static void print_help(void)
412: {
413: printf(
414: "netlink - Netlink statistic collector for Linux\n" \
415: "\n" \
416: " Powerful statistic collector for Linux using netlink sockets\n" \
417: " to collect link and traffic control statistics.\n" \
418: " Author: Thomas Graf <tgraf@suug.ch>\n" \
419: "\n" \
420: " Options:\n" \
421: " notc Do not collect traffic control statistics\n" \
422: " map=FILE Translate handles to map using a mapfile\n" \
423: "\n" \
424: " Map File format:\n" \
425: " # comment\n" \
426: " <handle> <name> # midline comment\n");
427: }
428:
429: static void netlink_set_opts(tv_t *attrs)
430: {
431: while (attrs) {
432: if (!strcasecmp(attrs->type, "notc"))
433: c_notc = 1;
434: else if (!strcasecmp(attrs->type, "map"))
435: c_mapfile = attrs->value;
436: else if (!strcasecmp(attrs->type, "help")) {
437: print_help();
438: exit(0);
439: }
440: attrs = attrs->next;
441: }
442: }
443:
444: static struct input_module netlink_ops = {
445: .im_name = "netlink",
446: .im_read = netlink_read,
447: .im_shutdown = netlink_shutdown,
448: .im_set_opts = netlink_set_opts,
449: .im_probe = netlink_probe,
450: .im_init = netlink_do_init,
451: };
452:
453: static void __init netlink_init(void)
454: {
455: register_input_module(&netlink_ops);
456: }
457:
458: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>