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